具有通配符类型参数的 Map 上的 flatMap

2024-01-09

我正在尝试写这样的东西:

trait Typed[T]

trait Test {

  def testMap: Map[Typed[_], Int]

  def test = testMap.flatMap {case (typed, size) => Seq.fill(size)(typed)}
}

但我收到以下错误:

error: no type parameters for method flatMap: (f: ((Typed[_], Int)) => Traversable[B])(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Map[com.quarta.service.querybuilder.Typed[_],Int],B,That])That exist so that it can be applied to arguments (((Typed[_], Int)) => Seq[Typed[_0]] forSome { type _0 })
--- because ---
argument expression's type is not compatible with formal parameter type;
found   : ((Typed[_], Int)) => Seq[Typed[_0]] forSome { type _0 }
required: ((Typed[_], Int)) => Traversable[?B]
def test = testMap.flatMap {case (typed, size) => Seq.fill(size)(typed)}

如果将 testMap 类型更改为:

def testMap: Map[Typed[Any], Int]

有什么区别以及如何解决我的问题?


如果我正确理解你的问题,答案是:你可以这样做,如果Typed是协变的T, i.e. trait Typed[+T].

Example

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Typed[+T: Manifest] {
  override def toString = "Typed[" + implicitly[Manifest[T]].toString + "]"
}

trait Test {
  def testMap: Map[Typed[_], Int]

  def foo = testMap flatMap { case (t, s) => Seq.fill(s)(t) }
}

val bar = new Test { 
  def testMap = Map(new Typed[Double]() -> 3, new Typed[Int]() -> 5)
}

// Hit Ctrl-D

scala> bar.foo
res0: scala.collection.immutable.Iterable[Seq[Typed[Any]]] = List(Typed[Double], Typed[Double], Typed[Double], Typed[Int], Typed[Int], Typed[Int], Typed[Int], Typed[Int])

请注意,我已经做了Typed本例中的一个类以获得更好的输出。你当然可以坚持使用trait.

现在,为什么这里需要协方差?

协方差基本上意味着如果A <: B then X[A] <: X[B]。所以如果你声明testMap as Map[Typed[Any], Int] while Typed were 不变的,您不被允许通过,例如ATyped[Double] for a Typed[Any]虽然Double <: Any。在这里,scala编译器似乎正在取代_ with Any在协变的情况下(请参阅即兴评论以获取对此的详细说明)。

对于有关下划线的问题的解释,我会参考 Luigi 的答案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有通配符类型参数的 Map 上的 flatMap 的相关文章

随机推荐