我有一段代码正在计算一些系列:
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)(_+_)
有点模糊。有人帮忙!!
答案 0 :(得分:3)
这里
ps
是类型集合Stream,实际上是一个变量但是 如何将其称为ps(10000),因为它不是任何方法
可以致电ps(10000)
,因为Stream
有apply
方法(继承自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
关键字的情况下实例化案例类的方式类似,因为编译器会自动为您生成apply
和unapply
。
如果我们看一下更简单的重现:
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.cons。 ConsWrapper的参数是一个名字参数,因此它被懒惰地评估。
因此在#::运算符之后引用fs是有效的。我认为我们必须将val更改为lazy val,否则scala编译器会引发前向引用扩展到值fs的定义。