RHS 上的模式活页夹变量类型与 LHS 上的匹配模式不对应

Type of pattern binder variable on RHS does not correspond to matched pattern on LHS

为什么偏函数

val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
  case v@Warped(Engineer(name: String)) => v.asInstanceOf[Warped[Engineer]]
}

似乎需要 asInstanceOf 在 RHS 上进行转换,而以下则不需要

val engineers: PartialFunction[Crewmember, Engineer] = {
  case v@Engineer(name) => v
}

given

sealed trait Crewmember
case class Engineer(name: String) extends Crewmember
case class Commander(name: String) extends Crewmember

case class Warped[+A <: Crewmember](v: A)

val engineers: PartialFunction[Crewmember, Engineer] = {
  case v@Engineer(name) => v
}

val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
  case v@Warped(Engineer(name: String)) => v.asInstanceOf[Warped[Engineer]]
}

val crew: List[Crewmember] = 
  List(Engineer("Geordi"), Commander("Picard"), Engineer("Scott"), Commander("Kirk"))

val warpedCrew: List[Warped[Crewmember]] = 
  List(Warped(Engineer("Geordi")), Warped(Commander("Picard")), Warped(Engineer("Scott")), Warped(Commander("Kirk")))

crew collect engineers
// res0: List[Engineer] = List(Engineer(Geordi), Engineer(Scott))

warpedCrew collect warpedEngineers
// res1: List[Warped[Engineer]] = List(Warped(Engineer(Geordi)), Warped(Engineer(Scott)))

可以像这样避免使用 asInstanceOf 进行转换

case Warped(eng: Engineer) => Warped(eng) 

但我想知道为什么编译器不插入隐式 asInstanceOf 而是将 v 键入 Warped[Crewmember]

val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
  case v@Warped(Engineer(name: String)) => v 
}

Error: type mismatch;
 found   : Warped[Crewmember]
 required: Warped[Engineer]
      case v@Warped(Engineer(name: String)) => v

根据SLS 8.1.3: Pattern Binders

A pattern binder @ consists of a pattern variable and a pattern . The type of the variable is the static type implied by the pattern . This pattern matches any value matched by the pattern , and it binds the variable name to that value.

A pattern implies a type if the pattern matches only values of the type .

Warped(Engineer(name))在左边

case v@Warped(Engineer(name: String)) => v

有静态类型 Warped[Crewmember] 因为那是你在类型签名中写的

val warpedEngineers: PartialFunction[Warped[Crewmember], ...

因此,如果您在右侧只写 v,则类型不匹配。

Warped(Engineer(name))右边和左边

case Warped(Engineer(name)) => Warped(Engineer(name))

看起来很像,但因为它们有不同的类型而不同。他们实际上是 Warped[Crewmember](Engineer(name))Warped[Engineer](Engineer(name))。由于协方差 Warped[Engineer]Warped[Crewmember] 但反之则不然。

编译器如何猜测它应该在此处插入 asInstanceOf 而不应在 val x: Int = "a" 中插入?

如果您更改签名

val warpedEngineers: PartialFunction[Warped[Engineer], Warped[Engineer]] = {
  case v@Warped(Engineer(name)) => v
}

然后 v 的静态类型将是 Warped[Engineer] 并且代码将编译。

同样,如果您使用类型化模式

val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
  case v: Warped[Engineer] => v
}

然后 v 的静态类型将是 Warped[Engineer] 并且代码将编译。

中的规格模式v@Warped(Engineer(name))
val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
  case v@Warped(Engineer(name)) => ...
}

"implies" 输入 Warped[Crewmember] (因为签名)。