为什么Scala会返回但没有中断并继续


22

Scala没有breakcontinue,因此某些循环行为需要更多的思考。

尽早结束循环需要尾递归,异常或scala.util.control.Breaks(使用异常)。

这样做的理由是,就像一样goto,它们是使流量模糊的流程构造,可以用更好,更令人惊讶的方式来完成。

但似乎可以使用相同的论点return

为什么斯卡拉故意忽略breakcontinue,但不return


1
我可以想像,语言的作者考虑尾递归作为构建迭代的方式。我可以想象得到,break并且continue需要一些其他的清理机制。OTOH return是一种有序终止功能的方法,并且任何清理机制已经存在。
9000

1
breakable { for { break; } }只是事后的想法,可能远非有效。
乔普·艾根

因为使用功能实际上没有理由。在python中是一样的。每次使用带break的for循环时,您都可以编写一个函数,将循环放入函数中并使用return。我想不出一个关于干净代码的好主意的情况。为了提高性能,清理可能会更好,但是在scala中,性能并不是最高优先级。
2014年

2
这个问题看起来有一个答案在这里:stackoverflow.com/questions/3770989/...
迈克尔·肖

3
@PaulDraper:对答案break,并continue包含在你的问题,在你的问题的链接。所要提出的问题return恰恰是我链接的问题所针对的,并且至少在接受投票最多的答案中得到了回答。如果两个答案加在一起不能回答您的问题,也许您可​​以编辑问题以弄清楚。
迈克尔·肖

Answers:


16

中断并继续:

关于Scala的讨论中,马丁·奥德斯基(Martin Odersky)给出了在幻灯片22中不包括中断或继续的三个原因:

  • 它们有点必要。最好使用许多较小的功能。
  • 讨论如何与闭包交互。
  • 不需要它们!

然后他说:“我们可以完全在库中支持它们。” 在幻灯片23中,他给出了实现的代码break。尽管我不太清楚Scala可以肯定,但是看起来这张幻灯片上的简短代码片段是实现所需的全部内容break,并且continue可以用同样简短的代码来实现。

能够在库中实现类似这样的功能可以简化核心语言。

Martin Odersky,Lex Spoon和Bill Venners撰写的“ Scala编程第二版”中给出了以下解释:

您可能已经注意到没有提及breakcontinue。Scala省略了这些命令,因为它们不能与函数文字完全吻合...很明显,continuewhile循环内部是什么意思,但是在函数文字内部是什么意思?...有很多不使用break和进行编程的方法continue,并且如果您利用函数文字,这些替代方法通常可能比原始代码短。

返回:

由于return是一个动词,是执行某项操作的命令,因此return可能被认为在样式上势在必行。但是,它们也可以纯粹以函数/声明的方式看到:它们定义函数的返回值是什么(即使在具有多个返回的函数中,它们每个都仅给出部分定义)。

在同一本书中,他们说以下内容return

在没有任何显式return语句的情况下,Scala方法将返回该方法计算出的最后一个值。实际上,建议的方法样式是避免使用显式(尤其是多个)return语句。而是将每种方法都视为产生一个值并返回的值的表达式。

即使return没有使用语句,方法也会结束并返回一个值,因此闭包不会有问题,因为否则闭包将无法正常工作。

与函数文字的网格划分也没有问题,因为函数无论如何都要返回一个值。


2
关于回返,似乎确实存在一些轻微的危险:tpolecat.github.io/2014/05/09/return.html
bbarker

0

我认为先前的答案确实可以解决在上下文相对不受限制的情况下为Scala breakcontinue以语言范围定义语义的问题。

我写了一个小库,它定义breakcontinue在更受限的上下文:经由Scala的迭代过序列-推导。通过关注该上下文,我相信语义变得明确并且易于推理。

该库位于此处:https : //github.com/erikerlandson/breakable

这是一个简单的代码示例:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.