2014-11-24 59 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