【问题标题】:Why can I have an impossible case in the scala match?为什么我可以在 scala 比赛中遇到不可能的情况?
【发布时间】:2023-03-10 22:56:01
【问题描述】:

在下面的示例中,在第二个 case 中,我预计会出现与第一个 case 相同的编译错误,但它可以编译。为什么?

object CaseMatching extends App {

  case class Id(value: Long)
  object Id { val zero = Id(0) }
  case class Name(value: String)
  case class IdName(id: Id, name: Name)

  IdName(Id(0), Name("A")) match {
    case IdName(_, Id(0)  ) => // does not compile (as expected)
    case IdName(_, Id.zero) => // does compile (but should not ?)
    case IdName(Id.zero, _) => println("OK") // this is OK and will match
    case _ =>
  }

}

为什么相关? - 我花了一个小时的大部分时间来找出为什么从未遇到过以下情况:case TreeEntry(_, Some(child), _, _, NodeType.DIR, _, _) 那是因为 NodeType 在第 4 个字段中,而不是在第 5 个字段中。如果编译器告诉我,我将不胜感激!

【问题讨论】:

    标签: scala pattern-matching case-class


    【解决方案1】:

    最短的答案:使Name final 足以说服编译器zero 不是一个。请参阅this issue 和周围环境。

    它会在类型测试时发出警告,即 isInstanceOf:

    <console>:15: warning: fruitless type test: a value of type CaseMatching.Name cannot also be a CaseMatching.Id
               case IdName(_, _: Id) =>
                                 ^
    

    但不是在测试相等时,因为相等是普遍的。

    这是另一个好消息,case IdName(_, Id) =&gt;

    <console>:15: error: pattern type is incompatible with expected type;
     found   : CaseMatching.Id.type
     required: CaseMatching.Name
    Note: if you intended to match against the class, try `case _: Id`
               case IdName(_, Id) =>
                              ^
    

    你想要的是:

    scala> IdName(Id(0), Name("A")) match { case IdName(_, id: Id.zero.type) => }
    <console>:21: warning: fruitless type test: a value of type Name cannot also be a Id (the underlying of Id.zero.type)
                  IdName(Id(0), Name("A")) match { case IdName(_, id: Id.zero.type) => }
                                                                             ^
    

    单例类型只包含那个值,所以它使用eq 进行测试;作为类型测试,它也会发出警告。 (截至本周,它使用eq 而不是equals。)

    不确定这对你有多大影响,但是:

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    sealed trait Id { def value: Long }
    case class Nonzero(value: Long) extends Id
    case object Zero extends Id { val value = 0L }
    case class Name(value: String)
    case class IdName(id: Id, name: Name)
    
    // Exiting paste mode, now interpreting.
    
    scala> IdName(Zero, Name("A")) match { case IdName(_, Zero) => 1 }
    <console>:14: error: pattern type is incompatible with expected type;
     found   : Zero.type
     required: Name
                  IdName(Zero, Name("A")) match { case IdName(_, Zero) => 1 }
                                                                 ^
    

    【讨论】:

    • 我尝试将零作为编译时间常数,例如final val Zero = Id(0) 但它仍然可以编译。这种情况和简单地传递Id(0)有什么区别?您能否就如何避免因此而陷入错误提出建议?
    • @stoyanr 添加了带有问题链接的最短答案。您的评论:Id(0) 不是常量,因此您的语法不会改变任何内容。
    猜你喜欢
    • 1970-01-01
    • 2018-12-22
    • 1970-01-01
    • 2011-04-20
    • 2019-10-30
    • 1970-01-01
    • 2021-12-30
    • 2016-08-13
    • 2012-06-02
    相关资源
    最近更新 更多