2014-11-24 28 views
4

假设我们定义一个接口为:识别两个类型通配符相同

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) 
      ^

那么......为什么会发生这种情况呢?我知道如何解决这个问题。我只是好奇。谢谢!

回答

3

您未使用类型在这里,您正在使用通配符类型。这类似于Java的

List<?> list = null; 
list.add(list.get(0)); 

它不能编译,因为编译器在几个步骤的工作原理:

  1. ,则返回值n.value,编译器标记来表示通配符值。
  2. 方法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

3

让我们先看看Foo[X] forSome {type X}。这意味着:对于有T的所有事物类型,它们的类型为Foo [T]

注意T未明确映射到某种类型。所以它是一些未知的类型。

-Xprint:all编译给一些更多的信息

[email protected]:~/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#i是X。但n.value返回其他东西

+0

感谢您的详细解释! – 2014-11-24 10:52:41