我正在尝试创建某种异构映射,并提出以下代码
sealed trait Key[V]
case object LongKey extends Key[Long]
case class KeyValue[V](key: Key[V], value: V)
object KeyValue {
def values(key: Key[Long], kvs: List[KeyValue[_]]): List[Long] =
kvs.collect {
case KeyValue(LongKey, v) ⇒ v: Long // this compiles
case KeyValue(`key`, v) ⇒ v: Long // this doesn't
}
}
由于Key
是密封且不变的,我原本预计这两条线可以互换。
为什么第二种情况不能编译?
...: type mismatch;
found : _$1 where type _$1
required: Long
case KeyValue(`key`, v) ⇒ v: Long
答案 0 :(得分:1)
好问题。我最初认为这"应该"工作,但考虑:
val kv: KeyValue[_] = KeyValue[String](null, "a")
val key: Key[Long] = null
kv match {
case KeyValue(`key`, v) => v // returns String, not Long!
}
答案 1 :(得分:0)
嗯,这是类型系统保证您的功能正确的方式。
进行功能签名时,
def values(key: Key[Long], kvs: List[KeyValue[_]]): List[Long]
KeyValue[_]
表示KeyValue[Z] forSome { type Z }
当编译器进行类型推断时,无法确保返回值为List[Long]
,而不会将大小写匹配仅限制为KeyValue(LongKey, v)
。
如果您需要通用函数来收集值,可以按如下所示重写它。
def values[V](key: Key[V], kvs: List[KeyValue[V]]): List[V] =
kvs.collect {
case KeyValue(keyType, v) ⇒ v
}
另一方面,如果您想将它们仅限制为Long类型,则需要将函数签名更改为,
def values(key: Key[Long], kvs: List[KeyValue[Long]]): List[Long]
这样就可以在case KeyValue(key, v)
上进行模式匹配。因为编译器可以验证只能预期Long类型。