【问题标题】:Type of pattern binder variable on RHS does not correspond to matched pattern on LHSRHS 上的模式绑定变量类型与 LHS 上的匹配模式不对应
【发布时间】:2020-09-02 18:29:33
【问题描述】:

为什么偏函数

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

图案活页夹????@????由模式变量组成????和一个图案 ????。变量的类型???是静态类型???暗示的 图案 ????。此模式匹配任何值 ????与模式匹配 ??????,并将变量名绑定到该值。

一个模式????暗示一种类型????如果模式只匹配 类型??????。

【问题讨论】:

    标签: scala casting pattern-matching instanceof parameterized-types


    【解决方案1】:

    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)) => ...
    }
    

    “暗示”类型Warped[Crewmember](因为签名)。

    【讨论】:

    • 键入的模式case v: Warped[Engineer] =&gt; v 在说collect 中不起作用,因为类型擦除所以它不会选择刚刚变形的Engineers。关于 “编译器应该如何猜测它应该在此处插入 asInstanceOf 而不应该例如在 val x: Int = "a" 中?”,模式匹配不会扩展到 @987654347 的组合@ 所以它必须知道至少isInstanceOf[Wraped[_] 是真的并且inInstanceOf[Engineer] 是真的?
    • 仅仅因为v: Warped[T] 内部有Engineer 并不意味着T = Engineerv = Warped[CrewMember](Engineer("Isaac")) 将满足模式 (v.isInstanceOf[Warped[_]] &amp;&amp; v.v.isInstanceOf[Engineer]),但不会是 Warped[Engineer]。想想如果case class Warped[+T &lt;: Crewmember](v: T) { val oops: T }会出什么问题。
    • @DmytroMitin 编译器似乎在下面的val engineers: PartialFunction[Crewmember, Engineer] = { case v@Engineer(name) =&gt; v } 中插入了asInstanceOf,所以这里v 的类型不是由签名确定的。 case _ 与构造函数模式或类型化模式有何关系?
    • @MarioGalic 我可以猜到不同之处在于模式是单态还是多态。对于v@Engineer(name),类型为Engineer,对于v@Warped(Engineer(name)),类型为Warped[T] (T &gt;: Engineer),T 取自签名。请参阅此处的 cmets github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/nsc/… case _ 与构造函数模式或类型化模式有何关系? 我试图展示类似于 Engineer/Warped 的示例,并且应该明确被拒绝。我想制定精确的公式并不容易......
    • ... 规则为什么应该拒绝 val f: List[Any] =&gt; List[Int] = { case xs =&gt; xs } 而应该接受 val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = { case v@Warped(Engineer(name)) =&gt; v }。总有一些程序在运行时正确运行,但在编译时被拒绝 (val x: Int = if (true) 1 else "a")。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 2018-06-20
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 2020-11-15
    相关资源
    最近更新 更多