模式匹配中的 `@` 符号

80

考虑以下Person案例类:

scala> case class Person(name: String, age: Int) {}
defined class Person

...还有这个实例

scala> val b = Person("Kevin", 100)
b: Person = Person(Kevin,100)

有理由偏爱这段代码(带有 @)吗?

scala> b match {
     |    case p @ Person(_, age) => println("age")
     |    case _ => println("none")
     | }
age

...接下来的内容是什么?

scala> b match {
     |    case Person(_, age) => println("age")
     |    case _ => println("none")
     | }
age

也许我没有理解 @ 的意义/功能?

2个回答

130

只有在想要处理对象本身时才包括@。 因此:

that match{
  case p @ Person(_, age) if p != bill => age
  case Person(_, age) => age - 15
  case _ => println("Not a person")
}
否则,将没有包含它的真正意义。

4
你可以使用分号来指代对象本身。我想知道为什么不再重复使用“用分号来指代对象本身”这个表述? - Val
很好了解!在阅读这个答案之前,我会这样写:case p: Person if p != bill => p.age - erdavila
@erdavila,这没有任何问题。在某些圈子里甚至可能更受欢迎。 - wheaties
4
@Val 我花了很多时间思考这个问题,最近才弄明白。这是因为冒号(而不是分号)匹配类型,但并非所有提取器都这样做。如果你创建了一个自定义提取器,并将其嵌套在任何类型的另一个提取器中,你可能想引用自定义提取器所匹配的对象,但自定义提取器可能不知道该对象的类型名称,因此使用冒号不合适。 - acjay
1
关于使用不同语法进行模式匹配的更多信息,请查看:http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html - Christian Vielma

16

关于上述答案的评论。

考虑以下情况类。

case class Employee(name: String, id: Int, technology: String)

在进行模式匹配时。

case e @ Employee(_, _, "scala") => e.name // matching for employees with only scala technology ... it works

case x: Employee => x.name // It also works

case e: Employee(_, _, "scala") => e.name // matching for employees with only scala technology ... **wont't work**

7
这种情况不需要使用@结构。您可以使用case Employee(name, _, "scala") => name - GatesDA
1
虽然第一行不是必需的(根据之前的评论),但我非常感谢您简化的对比,使我能够理解区别。即使在学习Scala 8年后,这仍然是一个边缘案例,我也会忘记这个特定事物的工作原理和原因。 - chaotic3quilibrium

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接