【问题标题】:For loop in scala without sequence?scala中的for循环没有序列?
【发布时间】:2011-11-13 05:13:09
【问题描述】:

所以,在阅读“不耐烦的 Scala”时,我发现自己在想:你可以使用没有序列的 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 风格的 for 循环呢?

【问题讨论】:

    标签: scala for-loop while-loop sequence


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

        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 trait 中定义)组合的语法糖,具体取决于生成器的嵌套及其类型。您可以尝试编译一些循环并使用

        打印其编译器中间表示
        scalac -Xprint:refchecks
        

        看看它们是如何展开的。

        【讨论】:

        • 哇,一个具有挑战性的答案,但很好。我只是在学习 Scala,所以你使用了很多我几乎不熟悉的术语,但是谢谢。
        • fromTo 的定义可以通过在Stream(或Iterator)伴生对象上使用iterate 方法进一步简化。类似于:def fromTo(from: Int, to: Int) = Stream.iterate(from, to - from)(_ + 1)。但是使用from until to 更习惯用法,并且可以达到同样的效果。
        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多