2017-04-26 56 views
2

編譯此代碼類型別名和多個參數列表功能類型推斷

case class MyType() 
object TestMe extends App { 
    type Fun[T] = T => Int 
    def myFun[T](x: T): Int = ??? 
    def matcher[T](f: Fun[T])(p: T): Int = ??? 
    var f = myFun[MyType] _ 
    val p = MyType() 
    matcher(f)(p) 
} 

失敗,此錯誤:

Error:(16, 11) type mismatch; 
found : ... MyType => Int 
required: ... TestMe.Fun[T] 
    (which expands to) T => Int 
    matcher(f)(p) 

更改爲如下所示的代碼可以解決問題:

case class MyType() 
object TestMe extends App { 
    type Fun[T] = T => Int 
    def myFun[T](x: T): Int = ??? 
    def matcher[T](f: Fun[T])(p: T): Int = ??? 
    var f: Fun[MyType] = myFun[MyType] // <-- Explicit type 
    val p = MyType() 
    matcher(f)(p) 
} 

另外更改參數順序可修復問題:

case class MyType() 
object TestMe extends App { 
    type Fun[T] = T => Int 
    def myFun[T](x: T): Int = ??? 
    def matcher[T](p: T)(f: Fun[T]): Int = ??? // <-- Flipping the argument, so the first argument have explicitly the parametric type 
    var f = myFun[MyType] _ 
    val p = MyType() 
    matcher(p)(f) // <-- Calls with flipped arguments 
} 

我的理解(我猜是因爲我缺乏Scala知識)是'type'只是創建類型別名,但看起來不像那樣。 有人可以解釋編譯失敗的原因嗎?

感謝

回答

3

這是類型推斷,以及如何打字員在編譯時解析類型的限制。

在Scala中,類型可以在參數列表之間傳遞(而不是在它們內部)。當你T類型的首位p作爲第一個參數列表中的參數,類型確定可先綁定TMyType,然後第二個參數列表知道fFun[MyType],因爲它可以推斷T

|-- matcher(p)(f) : pt=Unit EXPRmode (site: method main in Test) 
| | | | |-- matcher(p) BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test) 
| | | | | |-- matcher BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test) 
| | | | | | [adapt] [T](p: T)(f: Fun[T])Int adapted to [T](p: T)(f: Fun[T])Int 
| | | | | | \-> (p: T)(f: Fun[T])Int 
| | | | | |-- p BYVALmode-EXPRmode-POLYmode (silent: method main in Test) 
| | | | | | \-> MyType 
| | | | | solving for (T: ?T) 
| | | | | \-> (f: Fun[MyType])Int 
| | | | |-- f : pt=Fun[MyType] BYVALmode-EXPRmode (site: method main in Test) 
| | | | | \-> MyType => Int 

其他的方式不起作用,編譯器不能推斷TMyType => Int類型的函數是MyType(記住,功能也可能在他們的參數類型被逆變):

-- matcher(f)(p) : pt=Unit EXPRmode (site: method main in Test) 
| | | | |-- matcher(f) BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test) 
| | | | | |-- matcher BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test) 
| | | | | | [adapt] [T](f: Fun[T])(p: T)Int adapted to [T](f: Fun[T])(p: T)Int 
| | | | | | \-> (f: Fun[T])(p: T)Int 
| | | | | |-- f : pt=Fun[?] BYVALmode-EXPRmode-POLYmode (silent: method main in Test) 
| | | | | | \-> MyType => Int 
| | | | | solving for (T: ?T) 
| | | | | [search #1] start `MyType => Int`, searching for adaptation to pt=(MyType => Int) => Fun[T] (silent: method main in Test) implicits disabled 
| | | | | [search #2] start `MyType => Int`, searching for adaptation to pt=(=> MyType => Int) => Fun[T] (silent: method main in Test) implicits disabled 

正如你所說,切換參數列表的工作。您還可以通過在matcher方法中聲明它來明確幫助編譯器推斷該類型:

matcher[MyType](f)(p)