Scala中的流

时间:2016-05-06 09:22:34

标签: scala stream

我有一段代码正在计算一些系列:

object Problem7 extends App {
  lazy val ps: Stream[Int] = 2 #:: Stream.from(3).filter(i =>
  ps.takeWhile(j => j * j <= i).forall(i % _ > 0))

  val r = ps(10000)
  println(r)
}

这里ps属于类型集合Stream,它实际上是一个变量,但是它可以像ps(10000)一样调用它,因为它不是任何方法,我还有一个表达式val fs:Stream[Int] = 0 #:: fs.scanLeft(1)(_ + _)在这里,我对于我们如何在变量本身中调用fs.scanLeft(1)(_+_)有点模糊。有人帮忙!!

2 个答案:

答案 0 :(得分:3)

  

这里ps是类型集合Stream,实际上是一个变量但是   如何将其称为ps(10000),因为它不是任何方法

可以致电ps(10000),因为Streamapply方法(继承自LinerSeqOptimized):

/** Selects an element by its index in the $coll.
 *  Note: the execution of `apply` may take time proportial to the index value.
 *  @throws `IndexOutOfBoundsException` if `idx` does not satisfy `0 <= idx < length`.
 */
def apply(n: Int): A = {
  val rest = drop(n)
  if (n < 0 || rest.isEmpty) throw new IndexOutOfBoundsException("" + n)
  rest.head
}

在Scala中的任何对象上调用()将使编译器在对象上查找apply方法。这与您在没有new关键字的情况下实例化案例类的方式类似,因为编译器会自动为您生成applyunapply

如果我们看一下更简单的重现:

def main(args: Array[String]): Unit = {
  val ps: Stream[Int] = Stream.from(1, 1)
  val r = ps(1)
  println(r)
}

编译器实际上在做:

val r = ps.apply(1)

集合的apply通常会在索引i处查找元素:

scala> val ps: Stream[Int] = Stream.from(1, 1)
ps: Stream[Int] = Stream(1, ?)

scala> val r = ps(1)
r: Int = 2

scala> val x = ps.apply(1)
x: Int = 2

如果您确实想查看编译器生成的内容:

object Problem7 extends Object {
    def main(args: Array[String]): Unit = {
      val ps: scala.collection.immutable.Stream = scala.`package`.Stream().from(1, 1);
      val r: Int = scala.Int.unbox(ps.apply(1));
      scala.this.Predef.println(scala.Int.box(r))
    };

    def <init>(): Problem7.type = {
      Problem7.super.<init>();
      ()
    }
  }
}

答案 1 :(得分:1)

对于问题的第二部分,

lazy val fs:Stream[Int] = 0 #:: fs.scanLeft(1)(_ + _)

用于构造流的#:: is cons运算符Stream.consConsWrapper的参数是一个名字参数,因此它被懒惰地评估。

因此在#::运算符之后引用fs是有效的。我认为我们必须将val更改为lazy val,否则scala编译器会引发前向引用扩展到值fs的定义。