9

让我想到的是为什么以下

<something> match { ... }

不能改写为

<something>.match({ ... })  # error: identifier expected but 'match' found.

我想这是因为它不可能match作为常规方法实现,但我不确定。或者也许是出于性能原因。

另外,既然宏可用,是否match可以使用宏来实现?(不是应该做,只是假设)

编辑:这似乎与什么是 scala 的实验性虚拟模式匹配器有关?; 感谢@om-nom-nom 指出。

4

2 回答 2

2

通过将它作为关键字,它不需要与类型 Any 相关联,因此编译器可以自由推断(部分)函数的输入类型。如果它是 Any 的方法,它将以 Function[A, B] 作为参数。

实际意义在于

3 match { case "foo" => "bar" }

导致编译错误“类型不匹配”

但是一个(类型无参数的)matchMethod;

3.matchMethod { case "foo" => "bar" }

导致运行时异常“scala.MatchError”

那么即使我们详细地显式地参数化了类型,我们仍然不会在以下情况下得到编译错误:

"foo".matchMethod[Int, String] { case 3 => "bar" }

相反,我们会得到运行时异常'java.lang.ClassCastException',因为我们必须使用.asInstanceOf。

另一个好处是语法高亮,匹配在代码中跳出比另一种方法更多,我相信这是值得的,因为模式匹配是 Scala 的关键部分,值得特别关注。

补充:出于类似的原因,您希望 try catch 是一个关键字构造,而不是一个将两个函数作为参数的函数。match 则与 catch 一致,这也与 Java 一致。

这个答案是对 Martin Odersky 的扩展,这是 TravisBrown 首先指出的

于 2013-11-09T13:12:07.873 回答
2

samthebest 的回答可能是真正的原因(我不知道,这不是我所熟悉的),但还有另一种看待它的方式更普遍地与函数式编程相关。

众所周知,函数式编程中的匹配可以在没有任何特殊语言特性的情况下完成(Church Encoding

trait List[+T] {
    def mmatch[R](nil: => R, cons: (T, List[T]) => R): R
}
object Nil extends List[Nothing] {
    def mmatch[R](nil: => R, cons: (Nothing, List[Nothing]) => R) = nil
}
class Cons[+T](head: T, tail: List[T]) extends List[T] {
    def mmatch[R](nil: => R, cons: (T, List[T]) => R) = cons(head, tail)
}

def sum(l: List[Int]): Int = l mmatch (
    nil = 0,
    cons = (x, xs) => x + sum(xs)
)

val list = new Cons(1, new Cons(2, Nil))

println(sum(list))

在这种解释中,当你写

sealed trait List[+T]
case object Nil extends List[Nothing]
case class Cons[+T](head: T, tail: List[T]) extends List[T]

这个词sealed是提供match功能的值/术语。

因此,阅读您的问题的一种方式是,为什么不这样做呢?为什么不从其他基本语言特性构建匹配,而不是提供句法匹配呢?

原因是语法match提供了一些人们喜欢的语法糖:

  • 重叠匹配函数:

    sealed trait A
    sealed trait B
    case object X extends A
    case object Y extends A with B
    case object Z extends B
    
  • 嵌套匹配函数:

    (1 :: 2 :: Nil) match {
        case x :: y :: Nil => ???
    }
    

    如果没有语法糖,这是非常尴尬的。你能行的; 在尝试实现单子提取器时,我尝试探索这种可能性;但它肯定不那么漂亮。

  • 自动选择开放式和封闭式匹配功能。

    也就是说,Scala 中的提取器类似于开放匹配函数,因为任何都可能因返回而失败None;编译器不会检查是否完整match,但您可以根据需要将多个链接在一起,Scala 会选择第一个。另一方面,sealed特征提供封闭匹配功能,并具有完整性检查的好处。这些需要由单独的函数提供,但 Scala 允许您match对两者使用相同的语法。

就我个人而言,我怀疑上述要求最终不需要为匹配提供特殊的句法支持。我怀疑其他更通用的语言特性最终会提供同样的好处,尤其是在嵌套匹配领域。match然而,目前用特殊语法直接解决问题更有意义。

于 2013-11-09T14:30:36.437 回答