当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Scala immutable.LazyList用法及代码示例


用法 一

final class LazyList[+A] extends AbstractSeq[A] with LinearSeq[A] with LinearSeqOps[A, LazyList, LazyList[A]] with IterableFactoryDefaults[A, LazyList] with Serializable

这个类实现了一个不可变的链表。我们称其为"lazy",因为它仅在需要时计算其元素。

元素被 memory ;也就是说,每个元素的值最多计算一次。

元素被计算in-order并且永远不会被跳过。换句话说,访问尾部会导致首先计算头部。

LazyList 有多懒惰?当您有一个类型为 LazyList 的值时,您还不知道列表是否为空。如果你知道它是非空的,那么你也知道头部已经被计算了。但尾巴本身就是 LazyList ,其 emptiness-or-not 可能仍未确定。

LazyList 可能是无限的。例如,LazyList.from(0) 包含所有自然数 0、1、2 等。对于无限序列,某些方法(例如 countsummaxmin )不会终止。

这是一个例子:

import scala.math.BigInt
object Main extends App {
  val fibs: LazyList[BigInt] =
    BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map{ n => n._1 + n._2 }
  fibs.take(5).foreach(println)
}

// prints
//
// 0
// 1
// 1
// 2
// 3

为了说明,让我们在定义 fibs 中添加一些输出,这样我们就可以看到发生了什么。

import scala.math.BigInt
object Main extends App {
  val fibs: LazyList[BigInt] =
    BigInt(0) #:: BigInt(1) #::
      fibs.zip(fibs.tail).map{ n =>
        println(s"Adding ${n._1} and ${n._2}")
        n._1 + n._2
      }
  fibs.take(5).foreach(println)
  fibs.take(6).foreach(println)
}

// prints
//
// 0
// 1
// Adding 0 and 1
// 1
// Adding 1 and 1
// 2
// Adding 1 and 2
// 3

// And then prints
//
// 0
// 1
// 1
// 2
// 3
// Adding 2 and 3
// 5

请注意,fibs 的定义使用 val 而不是 defLazyList 的 memory 要求我们有一个地方来存储信息,而 val 允许我们这样做。

关于 LazyList 语义的进一步说明:

- 尽管LazyList 在被访问时会发生变化,但这并不与它的不变性相矛盾。一旦记住这些值,它们就不会改变。尚未 memory 的值仍然是"exist",它们只是还没有被计算出来。

- 谨记备忘;如果你不小心,它会吃掉内存。这是因为 LazyList 的 memory 创建了一个很像 scala.collection.immutable.List 的结构。只要有东西抓住头部,头部就会抓住尾巴,以此类推。另一方面,如果头部没有任何东西(例如,如果我们使用 def 来定义 LazyList ),那么一旦不再直接使用它,它就会消失。

- 请注意,某些操作,包括 dropdropWhileflatMapcollect 可能会在返回之前处理大量中间元素。

这是另一个例子。让我们从自然数开始并迭代它们。

// We'll start with a silly iteration
def loop(s: String, i: Int, iter: Iterator[Int]): Unit = {
  // Stop after 200,000
  if (i < 200001) {
    if (i % 50000 == 0) println(s + i)
    loop(s, iter.next(), iter)
  }
}

// Our first LazyList definition will be a val definition
val lazylist1: LazyList[Int] = {
  def loop(v: Int): LazyList[Int] = v #:: loop(v + 1)
  loop(0)
}

// Because lazylist1 is a val, everything that the iterator produces is held
// by virtue of the fact that the head of the LazyList is held in lazylist1
val it1 = lazylist1.iterator
loop("Iterator1: ", it1.next(), it1)

// We can redefine this LazyList such that all we have is the Iterator left
// and allow the LazyList to be garbage collected as required.  Using a def
// to provide the LazyList ensures that no val is holding onto the head as
// is the case with lazylist1
def lazylist2: LazyList[Int] = {
  def loop(v: Int): LazyList[Int] = v #:: loop(v + 1)
  loop(0)
}
val it2 = lazylist2.iterator
loop("Iterator2: ", it2.next(), it2)

// And, of course, we don't actually need a LazyList at all for such a simple
// problem.  There's no reason to use a LazyList if you don't actually need
// one.
val it3 = new Iterator[Int] {
  var i = -1
  def hasNext = true
  def next(): Int = { i += 1; i }
}
loop("Iterator3: ", it3.next(), it3)

- 在前面的fibs 示例中,tail 完全有效的事实令人感兴趣。 fibs 有一个初始的 (0, 1, LazyList(...)) ,所以 tail 是确定性的。如果我们定义 fibs 使得只有 0 是具体已知的,那么确定 tail 的行为将需要评估 tail ,因此计算将无法进行,如以下代码所示:

// The first time we try to access the tail we're going to need more
// information which will require us to recurse, which will require us to
// recurse, which...
lazy val sov: LazyList[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 }

上面 fibs 的定义创建的对象数量超出了必要的数量,具体取决于您可能希望如何实现它。以下实现提供了更多的"cost effective" 实现,因为它有更直接的路由到数字本身:

lazy val fib: LazyList[Int] = {
  def loop(h: Int, n: Int): LazyList[Int] = h #:: loop(n, h + n)
  loop(1, 1)
}

头部、尾部以及列表是否为空最初可能是未知的。一旦其中任何一个被评估,它们都是已知的,但如果尾部是用 #::#::: 构建的,它的内容仍然不会被评估。相反,评估尾部内容被推迟到评估尾部空状态,头部或尾部。

延迟评估 LazyList 是否为空,直到需要它允许 LazyList 在调用 filter 时不即刻地评估任何元素。

只有当它被进一步评估时(可能永远不会!)任何元素都会被强制执行。

例如:

def tailWithSideEffect: LazyList[Nothing] = {
  println("getting empty LazyList")
  LazyList.empty
}

val emptyTail = tailWithSideEffect // prints "getting empty LazyList"

val suspended = 1 #:: tailWithSideEffect // doesn't print anything
val tail = suspended.tail // although the tail is evaluated, *still* nothing is yet printed
val filtered = tail.filter(_ => false) // still nothing is printed
filtered.isEmpty // prints "getting empty LazyList"

类型参数:

A

此惰性列表中包含的元素的类型。

也可以看看:

"Scala's Collection Library overview" section on LazyLists for more information.

伴生:

object

源码:

LazyList.scala

用法 二

object LazyList extends SeqFactory[LazyList]

此对象提供一组操作来创建 LazyList.

伴生:

class

源码:

LazyList.scala

相关用法


注:本文由纯净天空筛选整理自scala-lang.org大神的英文原创作品 immutable.LazyList。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。