2017-04-26 57 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)