所以,在我通过“Scala for the Impatient”的过程中,我发现自己在想:你能不用序列使用Scala for循环吗?
例如,本书中有一个练习要求您构建一个无法递增超过Integer.MAX_VALUE的计数器对象。为了测试我的解决方案,我编写了以下代码:
var c = new Counter
for( i <- 0 to Integer.MAX_VALUE ) c.increment()
这会抛出一个错误:序列不能包含多个Int.MaxValue元素。 在我看来,这意味着Scala首先分配和填充序列对象,值为0到Integer.MaxValue,然后在该序列对象上执行foreach循环。
我意识到我可以这样做:
var c = new Counter
while(c.value < Integer.MAX_VALUE ) c.increment()
但是有没有办法用for语句做一个传统的C-style for循环?
答案 0 :(得分:18)
事实上,0 to N
实际上并不填充从0
到N
的整数。它改为创建scala.collection.immutable.Range
的实例,它将其方法应用于动态生成的所有整数。
您遇到的错误仅仅是因为您必须能够将Int
的正面部分中的元素数量(无论它们是否存在)以保持length
的合同。 {1}}方法。 1 to Int.MaxValue
和0 until Int.MaxValue
一样正常。而后者是你的while循环正在做的事情(to
包括正确的端点,until
省略它。)
无论如何,由于Scala for
是一个非常不同(更通用)的生物,而不是C for
,简短的答案是否定的,你不可能做同样的事情。但你可以用for
做你想做的事情(尽管可能没有你想要的那么快,因为会有一些性能损失)。
答案 1 :(得分:5)
//start from 0, stop at 9 inclusive
for (i <- 0 until 10){
println("Hi " + i)
}
//or start from 0, stop at 9 inclusive
for (i <- 0 to 9){
println("Hi " + i)
}
正如雷克斯指出的那样,“to”包括正确的终点,“直到”省略它。
答案 2 :(得分:4)
是和否,这取决于你的要求。如果你问是否可以迭代一系列整数而不必先构建那个序列,那么你可以,例如使用流:
def fromTo(from : Int, to : Int) : Stream[Int] =
if(from > to) {
Stream.empty
} else {
// println("one more.") // uncomment to see when it is called
Stream.cons(from, fromTo(from + 1, to))
}
然后:
for(i <- fromTo(0, 5)) println(i)
通过定义hasNext和next来编写自己的迭代器是另一种选择。
如果你问是否可以使用'for'语法编写一个“本机”循环,即一个循环通过递增一些本机整数而不是迭代一个对象实例产生的值,那么答案是,据我所知,没有。您可能知道,'for'理解是对flatMap,filter,map和/或foreach(都在FilterMonadic特性中定义)的组合的语法糖,具体取决于生成器及其类型的嵌套。您可以尝试编译一些循环并使用
打印其编译器中间表示scalac -Xprint:refchecks
了解它们是如何扩展的。
答案 3 :(得分:2)
那里有很多这样的东西,但我现在不能用谷歌搜索它们。以下是非常规范的:
@scala.annotation.tailrec
def loop(from: Int, until: Int)(f: Int => Unit): Unit = {
if (from < until) {
f(from)
loop(from + 1, until)(f)
}
}
loop(0, 10) { i =>
println("Hi " + i)
}