Scala:通配符(类型参数)和集合的编译错误:"you may wish to investigate a wildcard type as"

Scala: compile error with wildcards (type parameters) and collections: "you may wish to investigate a wildcard type as"

假设我有一个名为 Box 的 class,它有一个类型参数,它有以下实用方法:

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[_]] forSome { type _ } = Set(Box$$anon@70e0accd)
"""<console>:14: warning: inferred existential type 
scala.collection.immutable.Set[Box[_]] forSome { type _ }, 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[_]] where type _
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

因为 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[_ >: _ with _]] forSome { type _; type _ } = List(Box(), Box())