Tia*_*HUo 267 for-loop scala tail-recursion break
我如何打破循环?
var largest=0
for(i<-999 to 1 by -1) {
for (j<-i to 1 by -1) {
val product=i*j
if (largest>product)
// I want to break out here
else
if(product.toString.equals(product.toString.reverse))
largest=largest max product
}
}
Run Code Online (Sandbox Code Playgroud)
如何将嵌套for循环转换为尾递归?
来自FOSDEM 2009 上的Scala Talk http://www.slideshare.net/Odersky/fosdem-2009-1013261在第22页:
打破并继续Scala没有它们.为什么?他们有点必要; 更好地使用许多较小的函数问题如何与闭包交互.他们不需要!
解释是什么?
Rex*_*err 363
你有三个(左右)选项来摆脱循环.
假设你要总和数字,直到总数大于1000.你试试
var sum = 0
for (i <- 0 to 1000) sum += i
Run Code Online (Sandbox Code Playgroud)
除了你想要停止时(总和> 1000).
该怎么办?有几种选择.
(1a)使用包含您测试的条件的一些构造.
var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)
Run Code Online (Sandbox Code Playgroud)
(警告 - 这取决于在评估期间takeWhile测试和foreach是如何交错的细节,并且可能不应该在实践中使用!).
(1b)使用尾递归而不是for循环,利用在Scala中编写新方法的容易程度:
var sum = 0
def addTo(i: Int, max: Int) {
sum += i; if (sum < max) addTo(i+1,max)
}
addTo(0,1000)
Run Code Online (Sandbox Code Playgroud)
(1c)回到使用while循环
var sum = 0
var i = 0
while (i <= 1000 && sum <= 1000) { sum += 1; i += 1 }
Run Code Online (Sandbox Code Playgroud)
(2)抛出异常.
object AllDone extends Exception { }
var sum = 0
try {
for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone }
} catch {
case AllDone =>
}
Run Code Online (Sandbox Code Playgroud)
(2a)在Scala 2.8+中,这已经预先打包scala.util.control.Breaks使用的语法看起来很像你熟悉的C/Java旧版:
import scala.util.control.Breaks._
var sum = 0
breakable { for (i <- 0 to 1000) {
sum += i
if (sum >= 1000) break
} }
Run Code Online (Sandbox Code Playgroud)
(3)将代码放入方法并使用return.
var sum = 0
def findSum { for (i <- 0 to 1000) { sum += i; if (sum>=1000) return } }
findSum
Run Code Online (Sandbox Code Playgroud)
由于至少有三个我能想到的原因,故意这样做并不容易.首先,在大型代码块中,很容易忽略"继续"和"中断"语句,或者认为你的实际情况比实际情况更多或更少,或者需要打破两个你不能做的循环很容易 - 因此标准用法虽然方便,但却存在问题,因此您应该尝试以不同的方式构建代码.其次,Scala有各种各样的嵌套,你可能甚至都没有注意到,所以如果你能解决问题,你可能会对代码流的最终结束感到惊讶(尤其是关闭).第三,Scala的大多数"循环"实际上并不是正常循环 - 它们是具有自己的循环的方法调用,或者它们是递归,可能实际上也可能不是循环 - 尽管它们是循环的,但它很难想出一个一致的方法来了解"休息"等应该做什么.所以,为了保持一致,更明智的做法就是不要有"休息".
注意:所有这些都具有功能等价物,您可以返回值sum而不是将其变异.这些是更惯用的Scala.但是,逻辑仍然是一样的.(return变得return x等).
hoh*_*uli 64
这在Scala 2.8中有所改变,它具有使用休息的机制.您现在可以执行以下操作:
import scala.util.control.Breaks._
var largest = 0
// pass a function to the breakable method
breakable {
for (i<-999 to 1 by -1; j <- i to 1 by -1) {
val product = i * j
if (largest > product) {
break // BREAK!!
}
else if (product.toString.equals(product.toString.reverse)) {
largest = largest max product
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 29
打破for循环永远不是一个好主意.如果您使用for循环,则意味着您知道要迭代的次数.使用具有2个条件的while循环.
例如
var done = false
while (i <= length && !done) {
if (sum > 1000) {
done = true
}
}
Run Code Online (Sandbox Code Playgroud)
Pat*_*ick 13
要添加Rex Kerr,请回答另一种方法:
(1c)你也可以在循环中使用一个守卫:
var sum = 0
for (i <- 0 to 1000 ; if sum<1000) sum += i
Run Code Online (Sandbox Code Playgroud)我们在 scala 中可以做的就是
scala> import util.control.Breaks._
scala> object TestBreak {
def main(args : Array[String]) {
breakable {
for (i <- 1 to 10) {
println(i)
if (i == 5)
break;
} } } }
Run Code Online (Sandbox Code Playgroud)
输出 :
scala> TestBreak.main(Array())
1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)
由于breakScala中还没有,你可以尝试使用return-statement 来解决这个问题.因此,您需要将内部循环放入函数中,否则返回将跳过整个循环.
然而,Scala 2.8包含了一种打破方式
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
小智 5
// import following package
import scala.util.control._
// create a Breaks object as follows
val loop = new Breaks;
// Keep the loop inside breakable as follows
loop.breakable{
// Loop will go here
for(...){
....
// Break will go here
loop.break;
}
}
Run Code Online (Sandbox Code Playgroud)
使用Break模块 http://www.tutorialspoint.com/scala/scala_break_statement.htm
只需使用while循环:
var (i, sum) = (0, 0)
while (sum < 1000) {
sum += i
i += 1
}
Run Code Online (Sandbox Code Playgroud)
一种方法,它在迭代时生成一个范围内的值,直到达到破坏条件为止,而不是先生成整个范围,然后使用进行迭代Iterator(在@RexKerr中得到启发Stream)
var sum = 0
for ( i <- Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i
Run Code Online (Sandbox Code Playgroud)