假设我有一个名为 Box
的类,带有类型参数,它具有以下实用方法:
class Box[T]
object Box {
def build() : Box[_] = ???
def combine(boxes: Set[Box[_]]) : Unit = ???
}
我正在尝试以多种方式使用这些方法。有些会编译,有些则不会:
// 1
Box.combine(Set(Box.build())) // compiles
// 2
val boxes : Set[Box[_]] = Set(Box.build())
Box.combine(boxes) // compiles
// 3
val boxes2 = Set(Box.build())
Box.combine(boxes2) // compile error - "type mismatch... you may wish to investigate a wildcard type as `_ <: Box`"
如果 T
是协变的,那么一切都会编译。
这里发生了什么?为什么这种方法不能编译?我猜这与隐式转换有关,不是吗?
最佳答案
scala> val boxes2 = Set(Box.build())
boxes2: scala.collection.immutable.Set[Box[_$1]] forSome { type _$1 } = Set(Box$$anon$1@70e0accd)
"""<console>:14: warning: inferred existential type
scala.collection.immutable.Set[Box[_$1]] forSome { type _$1 }, which
cannot be expressed by wildcards, should be enabled
by making the implicit value scala.language.existentials visible.
This can be achieved by adding the import clause 'import
scala.language.existentials'
or by setting the compiler option -language:existentials."""
scala> Box.combine(boxes2)
"""<console>:16: error: type mismatch;
found : scala.collection.immutable.Set[Box[_$1]] where type _$1
required: Set[Box[_]]"""
scala> val boxes3: Set[Box[_]] = Set(Box.build())
scala> Box.combine(boxes3) // OK
编译器将存在类型推断为外部类型,因此结果对象的类型不适合combine
def check[A,B](implicit ev: A =:= B) = true
check[Set[Box[_]], Set[Box[t] forSome { type t }]] // true
check[Set[Box[_]], Set[Box[t]] forSome { type t }] // ERROR
as Set[Box[t] forSome { type t }]
与 Set[Box[t]] forSome { type t }
不同
但是,类型差异在这里也发挥着作用:
def f: Box[_] = Box[Int]() // Box is invariant in its type arg
def g: List[_] = List[Int]() // List is covariant in its type arg
f // Box[_] = Box()
g // List[Any] = List()
Set(f,f) // ERROR: type mismatch (as Set is invariant)
Set(g,g) // OK: scala.collection.immutable.Set[List[Any]] = Set(List())
List(f,f) // List[Box[_ >: _$1 with _$1]] forSome { type _$1; type _$1 } = List(Box(), Box())
关于Scala:通配符(类型参数)和集合的编译错误: "you may wish to investigate a wildcard type as",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34138789/