问题描述
特质类型[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在地图上使用通配符类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!