在模式匹配中键入参数推断

时间:2017-12-08 14:34:18

标签: scala

我正在尝试创建某种异构映射,并提出以下代码

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

2 个答案:

答案 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类型。

相关问题