2017-06-05 31 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