我很抱歉这样的非描述性标题,但我真的不知道如何更好地表达这一点。
class Foo[T]
Seq(new Foo[String], new Foo[Int]).groupBy(_ => 1).map { case (k, Seq(v)) => k -> v }.toMap
<console>:12: error: Cannot prove that (Int, Foo[_146]) forSome { type _146 >: Int with String } <:< (T, U).
WTF?
如果我使用.mapValues
代替.map
,则可行。此外,制作Foo
协变也会修复它,但在这种情况下,我最终会使用Map[Int,Foo[Any]]
这里发生了什么?有什么想法吗?
答案 0 :(得分:4)
如果没有差异,你会创建一个有点无意义的&#34;序列:
class Foo[T]
val in = Seq(new Foo[String], new Foo[Int]) // Seq[_ >: Int with String]]
Foo[String]
和Foo[Int]
之间根本没有共同的LUB。您可以为其指定一个存在类型:
val in = Seq[Foo[_]](new Foo[String], new Foo[Int])
然后我们可以尝试继续:
val in = Seq[Foo[_]](new Foo[String], new Foo[Int])
val g = in.groupBy(_ => 1) // Map[Int, Seq[Foo[_]]]
// the next line would produce a match error, thus make it a `def`
def m = g.map { case (k, Seq(v)) => k -> v } // Iterable[(Int, Foo[_])]
def p = m.toMap // cannot prove that (Int, Foo[_]) <:< (T, U)
再一次,存在主义类型在这里咬住了对价值类型的有用推断。您可以再次强制执行:
def p = m.toMap[Int, Foo[_]] // Map[Int,Foo[_]]
AFAIK,Scalac不会为您推断出存在类型。
如果您认为此处有Foo[Any]
,则需要添加方差注释:
class Foo[+T]
val in = Seq(new Foo[String], new Foo[Int]) // Seq[Foo[Any]]
def m = in.groupBy(_=>1).map {case (k,Seq(v)) => k->v}.toMap // Map[Int,Foo[Any]]