【问题标题】:Why val is stable identifier and def is not?为什么 val 是稳定的标识符,而 def 不是?
【发布时间】:2013-09-16 07:18:00
【问题描述】:

模式匹配时可以使用类实例的字段 (vals):

class A {
  val foo = 37
  def bar = 42
}

def patmat1(a: A, x: Int) {
  x match {
    case a.foo => println("a.foo")
    case _     => println("not a.foo")
  }
}

patmat1(new A, 37) // => a.foo
patmat1(new A, 42) // => not a.foo

我想知道为什么def不能类比使用?

def patmat2(a: A, x: Int) {
  x match {
    case a.bar => println("a.bar")
    //     ^ error: stable identifier required, but a.bar found.
    case _     => println("not a.bar")
  }
}

我认为valdef 大多可以互换。

【问题讨论】:

  • 嗯,val 是一个常量,而 def 是一个函数定义。它可以工作,但将空函数定义视为常量可能不是一个好主意......或者值得努力。
  • @marius 不,我认为这不是重复的。
  • @BoldizsárNémeth 这个问题的答案将完全相同。那么为什么这不是重复的呢?
  • 进一步调查:自定义unapply 的实现也可能取决于某些全局var 的状态。我认为def并不比unapply差。

标签: scala pattern-matching


【解决方案1】:

根据reference,您的第二种情况不是有效模式。 val foo 之所以有效,是因为它是一个稳定的标识符模式 § 8.1.5,这基本上意味着它会检查 x == a.foo 是否存在。

您的第二种情况根本不是任何有效的模式(因为 a.bar 不是标识符而是声明)因此错误。

一种惯用的方式是:

def patmat1(a: A, x: Int) {
  x match {
    case i if a.bar == x => println("a.foo")
    case _     => println("not a.foo")
  }
} 

【讨论】:

  • 稳定标识符是以标识符结尾的路径。 为什么a.bar 不是稳定标识符?我已经阅读了§ 8.1.5,但仍然不明白为什么禁止a.bar
  • a.bar 不是标识符而是声明
【解决方案2】:

我相信 case 语句左半部分的第一部分是解构一个对象或将其匹配到一个常量值。所以,例如:

val animal: Animal = Dog("butch",4)

animal match {
  case _: Dog => println("bow-wow")
  case _: Cat => println("meow")
}

如果你想和一个常量进行比较,你可以在 case 语句的主要部分进行:

secretConstant match {
  case Math.PI => println("I'm a PI")
  case Math.E  +> println("I'm an E")
  case _ => println("I don't know what I am")
}

但如果您想与计算值进行比较,则需要将其包含在 case 语句的 if 部分中:

tomsWeddingDate match {
  case date: LocalDate if date < LocalDate.now() => println("phew, I still have time to buy a gift.")
  case _ => println("Oops, I guess I need to send a belated card")
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 2013-06-05
    • 2017-03-27
    • 1970-01-01
    • 2014-07-11
    相关资源
    最近更新 更多