编译此代码
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'只是创建类型别名,但看起来并不像那样。 有人能解释编译失败的原因吗?
由于
答案 0 :(得分:3)
这是类型推断的限制以及typer在编译时如何解析类型。
在Scala中,类型可以在参数列表之间进行(而不是在它们内部)。当您首次将p
类型T
作为参数放在第一个参数列表中时,typer可以先将T
绑定到MyType
,然后知道第二个参数列表f
属于Fun[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
反过来说不起作用,编译器无法从T
类型的函数推断MyType
为MyType => Int
(请记住,函数在参数中也可能是逆变的型):
-- 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)