2013-11-20 63 views
1

我無法獲得帶有參數化類型的代碼以傳遞scala編譯器。我的目標是能夠表達(Predicate, Action)對,如MyProg對象所示。功能上的類型邊界

trait ProgBase { 
    type Predicate[T] = T => Boolean 
    type Action[T] = T => Unit 

    private var prog = List[(Predicate[Any], Action[Any])]() 

    final def on[T <: Any](pred: Predicate[T])(action: Action[T]) = { 
    prog = (pred, action) :: prog // gives type mismatch 
    } 

    // remainder of trait elided 
} 

object MyProg extends ProgBase { 
    on[String](s => !s.isEmpty) { s => 
    println(s + " is not empty") 
    } 

    on[Int](i => i.isValidByte) { i => 
    println(i + " can fit in a byte") 
    } 
} 

通過指定T有一個上限的Any,我希望這將安撫編譯器,但顯然我失去了一些東西:

[error] ......ProgBase.scala:8 type mismatch; 
[error] found : (T => Boolean, T => Unit) 
[error] required: (Any => Boolean, Any => Unit) 
[error]  prog = (pred, action) :: prog 
[error]       ^

回答

1

首先回答你的問題,如果你寫:

private var prog = List[(Predicate[_ <: Any], Action[_ <: Any])]() 

這一切都編譯好了。我們應該使用通配符,因爲元素的類型是未知的。

其次,也許你輸錯,你不能使用你的on功能,你使用它,使用它是這樣的:

on[String](s => !s.isEmpty)(s => !s.isEmpty) 

它引起類型不匹配:type Action[T] = T => Unit,但println具有類型Unit, 所以作爲一個變體,你可以簡單地寫:type Action = Unit。顯然,你可以避免使用這種類型的別名。

第三,也許你已經知道了,我shoudn't告訴你,其實你失去約謂詞類型的所有信息 - 讓我們檢查一下使用Scala的反思:

import scala.reflect.runtime.{universe => ru} 
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T] 

val s: String = "123" 
val i: Int = 123 

on[String](s => !s.isEmpty)(s => !s.isEmpty) 
on[Int](i => i.isValidByte)(i => i.isValidByte) 

getTypeTag((MyProg.prog.head._1)).tpe =:= ru.typeOf[(String) => Boolean] //>false! 

所以你看問題。

要處理它,你可以使用異構列表。列表和其他各種強大的結構,您可以在無形中找到:https://github.com/milessabin/shapeless

+0

通配符提示非常完美!是的,我打錯了行爲的主體,將解決。並感謝第三個問題,我想這是由於類型擦除。將看不成形。 – yotommy

+0

我想補充說,沒有必要使用'<:Any',因爲'Any'是所有類型的超類型。但是,在我看來,你知道這一點。 – DaunnC