本文介绍了flatMap在地图上使用通配符类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 特质类型[T] 

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

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

但是我得到以下错误:

 错误:方法flatMap没有类型参数:(f:((Typed [_],Int))=> Traversable [B])(隐式bf:scala.collection.generic.CanBuildFrom [scala.collection.immutable.Map [com.quarta.service.querybuilder.Typed [_],Int],B,That])存在这样的它可以应用于参数(((Typed [_],Int))=> Seq [Typed [_0]] for {some _0})
---因为---
参数表达式的类型与形式参数类型不兼容;
found :((Typed [_],Int))=> Seq [Typed [_0]] forSome {type _0}
required:((Typed [_],Int))=>遍历[?B]
def test = testMap.flatMap {case(typed,size)=> Seq.fill(size)(typed)}

如果将testMap类型更改为:

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

有什么区别以及如何解决我的问题? 如果我正确理解了你的问题,答案是:如果 Typed T 中是协变的, code> trait Typed [+ T] 。



示例



 阶> :粘贴
//进入粘贴模式(ctrl-D完成)
$ b $ class classd [+ T:Manifest] {
override def toString =Typed [+ implicitly [清单[T]]。toString +]
}

特性测试{
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]() - > new Typed [Int]() - > 5)
}

//按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 ,那么 X [A] 。因此,如果您将 testMap 声明为 Map [Typed [Any],Int] ,而 Typed 不变的,你不允许你通过例如a Typed [Double] 对于 Typed [Any] 即使 Double< ;: Any 。在这里,scala编译器似乎在协变的情况下用 Any 取代了 _ (详见extempore的评论这个)。



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


I'am trying to write something like this:

trait Typed[T]

trait Test {

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

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

But I get the following error:

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)}

This code works if change testMap type to:

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

What is the difference and how I can solve my problem?

解决方案

If I understood your question correctly, the answer is: You can do it if Typed is covariant in 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])

Note that I've made Typed a class in this example to get nicer output. You can of course stick with a trait.

Now, why is covariance needed here?

Covariance basically means that if A <: B then X[A] <: X[B]. So if you were declaring testMap as Map[Typed[Any], Int] while Typed were invariant, you were not allowed to pass in e.g. a Typed[Double] for a Typed[Any] even though Double <: Any. Here, the scala compiler seems to be replacing _ with Any in the covariant case (see extempore's comment for an elaboration on this).

For an explanation of the problem regarding the underscore, I'd refer to Luigi's answer though.

这篇关于flatMap在地图上使用通配符类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 06:16