【问题标题】:Weird compile error involving type parameters with a wildcard涉及带有通配符的类型参数的奇怪编译错误
【发布时间】:2017-11-06 08:56:34
【问题描述】:

抱歉,我无法将标题(或与此相关的问题)表述得比这更能提供信息,因为我不知道这里发生了什么。为什么这段代码无法编译:

 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]

这是什么?为什么我可以使用变量,但不能给它赋值??? 这对任何人都有意义吗?

【问题讨论】:

  • 你可以绑定通配符class Bak(val b: Bar[_ &lt;: Foo]),虽然我不知道为什么它会等待错误。即使将其设置为通配符 val 似乎也不起作用。
  • @MichaelZajac 好吧,是的......我也可以只做class Bak(val v: Bar[Foo]),因为协方差,这几乎是一样的。我认为,在这种情况下使用通配符的唯一原因是简洁——这样就不必拼出Foo .. 但是必须明确地写出边界会破坏这个目的:(
  • Bar[_] 根据 SLS 3.10 占位符语法默认为 Bar[_ &lt;: Any]。奇怪的是,错误只在被分配给一个值时才出现。

标签: scala generics wildcard covariance


【解决方案1】:

协变通配符类型,编译器会将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容器类型为_,由于List协变,所以编译器会将lres类型设置为@987654329 @。

并且由于您的代码 sn-p RupperboundFoo,所以 FooAny 之间会有冲突:

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

所以抛出了这个编译错误,在repl中它会自动将bak.b分配给一个临时res变量。

【讨论】:

  • 对,所以问题是,为什么在这种情况下将其设置为Any 而不是Foo。这是一个错误吗?
猜你喜欢
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 2014-09-25
  • 1970-01-01
  • 2010-09-27
  • 2012-07-01
相关资源
最近更新 更多