【发布时间】:2014-04-24 16:00:36
【问题描述】:
所以我为它们做了一些实用程序类和隐式转换。然而,当从 Seq 而不是从 Set 转换时,它工作得很好,尽管代码是相同的,而且这两个特征乍一看似乎非常相似。可能是什么问题,我该如何解决?
import scala.collection.mutable.HashMap
trait Indexed[T] {
def index: T
}
class IndexMap[T, V <: Indexed[T]] extends HashMap[T, V] {
override def put(key: T, value: V): Option[V] = {
require(key == value.index)
super.put(key, value)
}
final def put(value: V): Option[V] = put(value.index, value)
}
trait Named extends Indexed[String] {
final def index = name
def name: String
}
type NameMap[T <: Named] = IndexMap[String, Named]
这很好用:
implicit def seq2IndexMap[T, V <: Indexed[T]](s: Seq[V]): IndexMap[T,V] = {
val ret = new IndexMap[T,V]();
s.foreach(v => ret.put(v))
ret
}
但是,使用type mismatch; found : scala.collection.immutable.Set[Program.ClassData] required: Common.NameMap[Program.ClassData] (which expands to) Common.IndexMap[String,Common.Named] 编译失败
implicit def set2IndexMap[T, V <: Indexed[T]](s: Set[V]): IndexMap[T,V] = {
val ret = new IndexMap[T,V]();
s.foreach(v => ret.put(v))
ret
}
输入时:
val c = Class("Test", Set(ClassData("data1", null), ClassData("data2", null)))
ClassData 扩展 Named。
我使用的是 Scala 2.10。
编辑:
为方便起见,对 Class 和 ClassData 的简化定义:
case class ClassData(name: String, p: Any) extends Named
case class Class(n: String, data: NameMap[ClassData])
编辑 2:
好的,我们找到了问题。确实是因为Set 是不变的(我不明白为什么)。
当我写Set(ClassData("data1", null)) 时,它生成了一个Set[ClassData],它不能解释为Set[Named],而它与Seq 一起工作,因为Seq 是协变的。
有趣的是,当我们显式调用转换时,Scala 没有任何问题:
val c = Class("Test", set2IndexMap((Set(ClassData("data1", null), ClassData("data2", null))))
在这种情况下,我认为 Scala 能够推断出要推断的 Set 的类型。在我看来,这表明 Scala 可能过于复杂。如果我对显式版本也有错误,我可以立即看到隐式转换有什么问题。我觉得幕后发生的事情太多了,最终你必须了解它们,否则你会遇到这样的问题。
一种解决方案是明确说明集合的类型:
val c = Class("Test", Set[Named](ClassData("data1", null), ClassData("data2", null)))
更好的解决方案是使隐式转换适用于Iterable 甚至Traversable,它们是Seq 和Set 的超级特征,并且是 协变的(尽管@ 987654342@ 不是,同时是协变的作为 Iterable)。
implicit def set2IndexMap[T, V <: Indexed[T]](s: Traversable[V]): IndexMap[T,V] = {
val ret = new IndexMap[T,V]();
s.foreach(v => ret.put(v))
ret
}
【问题讨论】:
-
您的第一个代码块无法编译。哪个
HashMap已导入但未显示? -
它是 scala.collection.mutable.HashMap,因为你可以看到我对其进行了变异。
-
顺便说一句,您应该避免使用核心 Java 库名称,例如
Class(在 java.lang 中定义)。