scala 没有序列的scala中的for循环?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7352310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:26:35  来源:igfitidea点击:

For loop in scala without sequence?

scalafor-loopwhile-loopsequence

提问by Adam Ness

So, while working my way through "Scala for the Impatient" I found myself wondering: Can you use a Scala for loop without a sequence?

所以,在我完成“不耐烦的 Scala”的过程中,我发现自己在想:你可以使用 Scala for 循环而不使用序列吗?

For example, there is an exercise in the book that asks you to build a counter object that cannot be incremented past Integer.MAX_VALUE. In order to test my solution, I wrote the following code:

例如,书中有一个练习要求您构建一个计数器对象,该对象不能递增超过 Integer.MAX_VALUE。为了测试我的解决方案,我编写了以下代码:

var c = new Counter
for( i <- 0 to Integer.MAX_VALUE ) c.increment()

This throws an error: sequences cannot contain more than Int.MaxValue elements. It seems to me that means that Scala is first allocating and populating a sequence object, with the values 0 through Integer.MaxValue, and then doing a foreach loop on that sequence object.

这会引发错误:序列不能包含多个 Int.MaxValue 元素。在我看来,这意味着 Scala 首先分配和填充序列对象,值从 0 到 Integer.MaxValue,然后在该序列对象上执行 foreach 循环。

I realize that I could do this instead:

我意识到我可以这样做:

var c = new Counter
while(c.value < Integer.MAX_VALUE ) c.increment()

But is there any way to do a traditional C-style for loop with the for statement?

但是有没有办法用 for 语句做一个传统的 C 风格的 for 循环?

回答by Rex Kerr

In fact, 0 to Ndoes not actually populate anything with integers from 0to N. It instead creates an instance of scala.collection.immutable.Range, which applies its methods to all the integers generated on the fly.

事实上,实际上0 to N并没有用整数从0to填充任何东西N。相反scala.collection.immutable.Range,它创建了一个 的实例,该实例将其方法应用于动态生成的所有整数。

The error you ran into is only because you have to be able to fit the number of elements (whether they actually exist or not) into the positive part of an Intin order to maintain the contract for the lengthmethod. 1 to Int.MaxValueworks fine, as does 0 until Int.MaxValue. And the latter is what your while loop is doing anyway (toincludes the right endpoint, untilomits it).

您遇到的错误只是因为您必须能够将元素的数量(无论它们是否实际存在)放入 an 的正数部分,Int以维护该length方法的契约。 1 to Int.MaxValue工作正常,就像0 until Int.MaxValue。后者就是你的 while 循环正在做的事情(to包括正确的端点,until省略它)。

Anyway, since the Scala foris a very different (much more generic) creature than the C for, the short answer is no, you can't do exactly the same thing. But you can probably do what you want with for(though maybe not as fast as you want, since there is some performance penalty).

无论如何,由于 Scalafor是一种与 C 非常不同(更通用)的生物for,因此简短的回答是否定的,您不能做完全相同的事情。但是你可能可以做你想做的事for(虽然可能没有你想要的那么快,因为有一些性能损失)。

回答by user85116

Wow, some nice technical answers for a simple question (which is good!) But in case anyone is just looking for a simple answer:

哇,一个简单问题的一些很好的技术答案(很好!)但万一有人只是在寻找一个简单的答案:

//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)
}

As Rex pointed out, "to" includes the right endpoint, "until" omits it.

正如 Rex 指出的那样,“to”包括正确的端点,“until”省略它。

回答by Philippe

Yes and no, it depends what you are asking for. If you're asking whether you can iterate over a sequence of integers without having to build that sequence first, then yes you can, for instance using streams:

是和否,这取决于您的要求。如果您问是否可以迭代整数序列而不必先构建该序列,那么您可以,例如使用流:

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))
  }

Then:

然后:

for(i <- fromTo(0, 5)) println(i)

Writing your own iterator by defining hasNext and next is another option.

通过定义 hasNext 和 next 来编写自己的迭代器是另一种选择。

If you're asking whether you can use the 'for' syntax to write a "native" loop, i.e. a loop that works by incrementing some native integer rather than iterating over values produced by an instance of an object, then the answer is, as far as I know, no. As you may know, 'for' comprehensions are syntactic sugar for a combination of calls to flatMap, filter, map and/or foreach (all defined in the FilterMonadictrait), depending on the nesting of generators and their types. You can try to compile some loop and print its compiler intermediate representation with

如果您问是否可以使用“for”语法来编写“本机”循环,即通过增加一些本机整数而不是迭代对象实例产生的值来工作的循环,那么答案是,据我所知,没有。您可能知道,'for' 推导式是对 flatMap、filter、map 和/或 foreach(均在FilterMonadictrait 中定义)的组合调用的语法糖,具体取决于生成器的嵌套及其类型。您可以尝试编译一些循环并打印其编译器中间表示

scalac -Xprint:refchecks

to see how they are expanded.

看看它们是如何扩展的。

回答by Derek Wyatt

There's a bunch of these out there, but I can't be bothered googling them at the moment. The following is pretty canonical:

那里有很多这样的东西,但我现在懒得用谷歌搜索它们。以下是非常规范的:

@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)
}