2017-06-05 33 views
3

我很抱歉,我無法制定標題(或有關此問題的問題),因爲我不知道這裏發生了什麼。爲什麼不編碼:奇怪的編譯錯誤涉及帶有通配符的類型參數

class Foo 
class Bar[+R <: Foo] { def bar = "bar" } 
class Bak(val b: Bar[_]) 
val bak = new Bak(new Bar[Foo]) 
bak.b.bar // fine 
println(bak.b) // fine 
bak.b // oops! 
^^^ type arguments [Any] do not conform to class Bar's type parameter bounds [+R <: Foo] 

這是什麼?爲什麼我可以使用該變量,但不能將它分配給一個val? 這對任何人都有意義嗎?

+1

你可以綁定通配符類Bak(val b:Bar [_ <:Foo])',儘管我不知道它爲什麼會等待錯誤。即使將它設置爲通配符val似乎也不起作用。 –

+0

@MichaelZajac很好,是的......我也可以做'class Bak(val v:Bar [Foo])',因爲協變性,這幾乎是相同的東西。我認爲,在這種情況下使用通配符的唯一原因是簡潔 - 所以人們不必拼寫出'Foo'..但是必須明確寫出邊界來否定該目的:( – Dima

+0

'Bar [_]'默認爲'Bar [_ <:Any]'根據SLS 3.10佔位符的語法,這很奇怪,錯誤只在分配給某個值時才顯示出來 –

回答

0

協變通配符類型,編譯器將所述res的容器類型設置爲Any,如:

scala> val l: List[_] = List(123) 
l: List[_] = List(123) 
scala> l 
res1: List[Any] = List(123) 
scala> :type l 
List[Any] 

作爲上述代碼,List容器類型是_,並且由於Listcovariant,所以編譯器會將lres類型設置爲List[Any]

隨着您的代碼段R上界Foo,所以會出現與AnyFoo之間的衝突:

val res: Bar[Any] = bak.b //+R <: Foo 

所以這編譯錯誤被扔在REPL它會自動分配bak.b到臨時變量res變量。

+0

正確,所以問題是,爲什麼它將它設置爲'Any'在這種情況下,而不是'Foo'。這是一個錯誤嗎? – Dima