當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。