我正试图写这样的东西:
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]
有什么区别以及如何解决我的问题?
答案 0 :(得分:5)
如果我正确理解了您的问题,答案是:如果Typed
中的T
是协变的,即trait Typed[+T]
,则可以执行此操作。
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
那么X[A] <: X[B]
。因此,如果您将testMap
声明为Map[Typed[Any], Int]
而Typed
不变,则不允许您传递,例如即使Typed[Double]
,Typed[Any]
的{{1}}也是Double <: Any
。在这里,scala编译器似乎在协变情况下用_
替换Any
(请参阅extempore的注释以详细阐述)。
有关下划线问题的解释,我会参考Luigi的答案。
答案 1 :(得分:4)
我认为问题是你试图将匿名函数与存在类型参数进行模式匹配。
从语言规范,第8.5节关于模式匹配匿名函数:
必须部分定义此类表达式的预期类型。它 某些
scala.Functionk[S1, ... , Sk, R]
必须为k > 0
,或者scala.PartialFunction[S1, R]
,参数type(s) S1, ... , Sk
必须完全确定,但结果类型R
可能是 未确定。
testMap
是一种存在类型(参见语言规范3.2.10)。存在类型的格式为T forSome {Q}
,其中Q是类型声明的序列。您使用了特殊占位符语法,因此类型Map[Typed[_], Int]
等同于Map[Typed[t] forSome { type t }, Int]
,这可能会使错误消息更有意义。
至于解决方案,我想这完全取决于你想要做什么,你不会说......:)
答案 2 :(得分:0)
参数化测试不是一个选项吗?
trait Test [A] {
def testMap: Map [Typed [A], Int]
def test = testMap.flatMap {case (typed, size) => Seq.fill (size)(typed)}
}
在知道A将会是什么之前,您是否必须申报测试?