假设我们将接口定义为:
trait Foo[A] {
val value: A
def perform(v: A): Unit
}
并编译此代码:
val n: Foo[_] = null
n.perform(n.value)
它看起来很完美......但是我们得到了一个神秘的错误:
error: type mismatch;
found : n.value.type (with underlying type _$1)
required: _$1
n.perform(n.value)
^
那么......为什么会这样?我知道怎么解决这个问题;我只是好奇。谢谢!
答案 0 :(得分:3)
您在此处未使用原始类型,您使用的是通配符类型。这类似于Java的
List<?> list = null;
list.add(list.get(0));
它不能编译,因为编译器分几步工作:
n.value
,编译器将该值标记为表示通配符。n.perform
,编译器只知道该参数是另一个通配符。然而,两个通配符不一定相同。相反,发布了两个通配符。要进行此调用,您需要应用所谓的get-and-put principle。 get-put原则基本上意味着您临时命名通配符类型,以便Scala编译器可以推断两个通配符是相同的。这样做,以下代码编译:
val n: Foo[_] = null
def rebox[A](x: Foo[A]) = x.perform(x.value)
rebox(n)
并抛出NullPointerException
。
答案 1 :(得分:3)
让我们先看看Foo[X] forSome {type X}
。这意味着:对于存在某些T的所有事物的类型,它们的类型为Foo [T]
注意T
未显式映射到某种类型。所以它是一些未知的类型。
使用-Xprint:all
进行编译会提供更多信息
jatinpuri@jatin:~/Desktop$ scalac -Xprint:all T.scala
[[syntax trees at end of parser]] // T.scala
package <empty> {
...
abstract trait Foo[A] extends scala.AnyRef {
val value: A;
def perform(v: A): Unit
};
val n: Foo[_$1] forSome {
<synthetic> type _$1
} = null;
n.perform(n.value)
}
}
因此n.value
会返回_$1
类型。但是n.perform()也期望一个狂野类型。两种未知类型不能相同。进一步解释:
scala> trait Foo[A] {
| val value: A
| def perform(v: A): Unit
| type i = A
| }
defined trait Foo
scala> type I = Foo[X] forSome {type X}
defined type alias I
scala> val n : I = null;
n: I = null
scala> n.value:(I#i)
<console>:16: error: type mismatch;
found : n.value.type (with underlying type X)
required: X
n.value:(I#i)
我#i是X
。但是n.value返回别的东西