在泛型方法通过下划线方式转换为部分应用函数(偏应用函数)的时候,类型推导有一个细节。我们先看返回值是泛型(参数化)的情况:
泛型参数T
会被编译器约束为 T >: Nothing <: Any
,即上限是Any
,下限是Nothing
.
scala> def method[T]():T = null.asInstanceOf[T]
method: [T]()T
scala> val f = method _
f: () => Nothing = <function0>
如上,在只有结果类型是参数化类型的情况下,因为Function0
的返回值类型声明为协变的,从里氏替换的角度,编译器进行推导时T会选用最底层的类型,这个类型是Nothing
。
scala> def method[T](p:T) = println("ok")
method: [T](p: T)Unit
scala> val f = method _
f: Any => Unit = <function1>
如上,在只有方法参数是参数化类型的情况下,因为Function1
的参数类型声明是逆变的,从里氏替换的角度,编译器进行推导时T会选用最上层的类型,这个类型是Any
。
而若方法的参数和返回值都用参数化类型表示时,则类型推导选择的是都是Nothing
,而非入参是 Any
,返回值是Nothing
这种不一致的行为。
scala> def method[T](p:T) = p
method: [T](p: T)T
scala> val f = method _
f: Nothing => Nothing = <function1>
归根到底,是因为scala/java的方法支持泛型(具备类型参数化多态),而scala的函数却在构造时需要具体的输入和输出类型,所以在从方法转换为函数的过程时必然是有所损失的。
而若方法的参数和返回值都用参数化类型表示时,则类型推导选择的是都是Nothing,而非入参是 Any,返回值是Nothing 这种不一致的行为。
scala> def method[T](p:T) = p
method: [T](p: T)T
这段应该是
scala> def method[T](p:T):T= p
method: [T](p: T)T
少了个返回值吧?
这种情况下返回值类型可省略,编译器的推断返回类型也肯定是T。
Pingback引用通告: scala类型系统:类型推导 | 在路上