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

标签 scala generics type-conversion covariance type-parameter

假设我有一个名为 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/

相关文章:

scala - 我可以用 scala.Singleton 做什么?

swift - 如何使用父类(super class)中声明的方法返回子类的实例?

java - 了解 Java 中的泛型和比较

java - Java 泛型和原始非参数化类型的混淆编译错误

arrays - 转换字符串?

c++ - 不允许对自定义类型进行多次隐式转换?

scala - 如何使用Scala在ElasticSearch中获取_delete_by_query api的状态

scala - 如何使用 Play 2.4 将服务注入(inject)到 Actor 中?

scala - 未经授权的: You must be authenticated to access this page.-通过 Play 表格时

c# - 为什么我不能在条件运算符中返回具有共同祖先的兄弟类型?