向Scala添加“case”关键字背后的原因是什么?

时间:2013-10-19 22:06:22

标签: scala syntax pattern-matching

除了:

case class A

... 案例哪个非常实用?

为什么我们需要在case中使用match?不会:

x match {
  y if y > 0 => y * 2
  _ => -1
}

... 更漂亮,更简洁?

或者为什么我们需要在函数获取元组时使用case?说,我们有:

val z = List((1, -1), (2, -2), (3, -3)).zipWithIndex

现在,不是:

z map { case ((a, b), i) => a + b + i }

... 方式不仅仅是:

z map (((a, b), i) => a + b + i)

...

4 个答案:

答案 0 :(得分:10)

首先,正如我们所知,可以为同一个案例场景放置几个语句,而不需要一些分隔符号,只需一行跳转,如:

x match {
       case y if y > 0 => y * 2
                          println("test")
                          println("test2")  // these 3 statements belong to the same "case"
}

如果不需要case,编译器必须找到一种方法来了解下一个案例场景何时涉及一条线。

例如:

x match {
   y if y > 0 => y * 2
   _ => -1
}

编译器如何知道_ => -1是属于第一种情况还是代表下一种情况?

此外,编译器如何知道=>符号不代表文字函数,而是当前case的实际代码?

编译器当然需要一种这样的代码,允许案例隔离: (使用花括号或其他任何东西)

x match {
    {y if y > 0 => y * 2}
    {_ => -1}  // confusing with literal function notation
}

当然,使用case关键字的解决方案(目前由scala提供)比在我的示例中使用花括号等分隔方式更具可读性和可理解性。

答案 1 :(得分:8)

添加到@ Mik378的答案:

当你写这个:(a, b) => something时,你正在定义一个匿名的Function2 - 一个带有两个参数的函数。

当您写下这个:case (a, b) => something时,您正在定义一个匿名PartialFunction,它接受​​一个参数并将其与一对匹配。

因此,您需要case关键字来区分这两者。

答案 2 :(得分:2)

第二个问题,即避免case的匿名函数,是一个有争议的问题:

https://groups.google.com/d/msg/scala-debate/Q0CTZNOekWk/z1eg3dTkCXoJ

另外:http://www.scala-lang.org/old/node/1260

对于第一个问题,选择是否允许箭头的RHS上的块或表达式。

在实践中,我发现通常更喜欢较短的盒子体,所以我当然可以想象你的替代语法会产生更清晰的代码。

考虑单行方法。你写道:

def f(x: Int) = 2 * x

然后你需要添加一个声明。我不知道IDE是否能够自动添加parens。

def f(x: Int) = { val res = 2*x ; res }

这似乎并不比要求案例主体使用相同的语法更糟糕。

要查看,案例条款为case Pattern Guard => body

目前,body是一个块,或一系列语句和结果表达式。

如果body是表达式,则需要多个语句的大括号,如函数。

我不认为=>导致含糊不清,因为函数文字不符合模式,不像1"foo"这样的文字。

可能有一个障碍:{ case foo => ??? }是“匹配匿名函数的模式”(SLS 8.5)。显然,如果案例是可选的或被删除,则{ foo => ??? }是不明确的。您必须区分anon funs的案例子句(需要case)和match中的case子句。

当前语法的一个反驳论点是,在源自C的直觉中,你总是暗地希望你的匹配将编译到切换表。在那个比喻中,案例是跳转到的标签,标签只是一系列陈述的地址。

替代语法可能会鼓励采用更内联的方法:

x match {
  C => c(x)
  D => d(x)
  _ => ???
}
@inline def c(x: X) = ???
//etc

在这种形式中,它看起来更像是一个调度表,匹配体回忆Map语法Map(a -> 1, b -> 2),即整理关联的简化。

答案 3 :(得分:1)

代码可读性的一个关键方面是引起你注意的词。例如, return当你看到它时会抓住你的注意力,因为你知道这是一个决定性的动作(打破了这个功能并可能将一个值发回给调用者)。

另一个例子是break - 不是我喜欢break,而是引起了你的注意。

我同意@ Mik378,Scala中的case比其他选项更具可读性。除了他提到的编译混淆之外,它引起了你的注意。

我全都是为了简洁的代码,但简洁和难以辨认之间有一条线。我很乐意进行4n个字符的交易(其中 n 是案例的数量),以获得我得到的实质性可读性。