维基百科中惰性求值的解释
惰性求值(Lazy Evaluation),又称惰性计算、懒惰求值,是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。它有两个相关而又有区别的含意,可以表示为“延迟求值”和“最小化求值”,本条目专注前者,后者请参见最小化计算条目。除可以得到性能的提升外,惰性计算的最重要的好处是它可以构造一个无限的数据类型。
惰性求值的相反是及早求值,这是一个大多数编程语言所拥有的普通计算方式。
import scala.io.Source.fromFile
val iter: Iterator[String] =
fromFile("sampleFile")
.getLines()
文件迭代器就用到了惰性求值.
用户可以完全像操作内存中的数据一样操作文件,然而文件只有一小部分传入了内存中.
lazy val firstLazy = {
println("first lazy")
1
}
lazy val secondLazy = {
println("second lazy")
2
}
def add(a:Int,b:Int) = {
a+b
}
//在 scala repl 中的结果
scala> add(secondLazy,firstLazy)
second lazy
first lazy
res0: Int = 3
res0: Int = 3
second lazy 先于 first lazy输出了
def firstLazy = {
println("first lazy")
1
}
def secondLazy = {
println("second lazy")
2
}
def chooseOne(first: Boolean, a: Int, b: Int) = {
if (first) a else b
}
def chooseOneLazy(first: Boolean, a: => Int, b: => Int) = {
if (first) a else b
}
chooseOne(first = true, secondLazy, firstLazy)
//second lazy
//first lazy
//res0: Int = 2
chooseOneLazy(first = true, secondLazy, firstLazy)
//second lazy
//res1: Int = 2
对于非纯函数,惰性求值会产生和立即求值产生不一样的结果.
//需要查询mysql等,可能来自于一个第三方jar包
def itemIdToShopId: Int => Int
var cache = Map.empty[Int, Int]
def cachedItemIdToShopId(itemId: Int):Int = {
cache.get(itemId) match {
case Some(shopId) => shopId
case None =>
val shopId = itemIdToShopId(itemId)
cache += itemId -> shopId
shopId
}
}
//用你的本地mock来测试程序
def mockItemIdToSHopId: Int => Int
def cachedItemIdToShopId(itemId: Int): Int ={
cache.get(itemId) match {
case Some(shopId) => shopId
case None =>
val shopId = mockItemIdToSHopId(itemId)
cache += itemId -> shopId
shopId
}
}
//将远程请求的结果作为函数的一个参数
def cachedItemIdToShopId(itemId: Int, remoteShopId: Int): Int = {
cache.get(itemId) match {
case Some(shopId) => shopId
case None =>
val shopId = remoteShopId
cache += itemId -> shopId
shopId
}
}
//调用这个函数
cachedItemIdToShopId(itemId,itemIdToShopId(itemId))
没错,cache根本没有起应有的作用,函数每次执行的时候都调用了itemIdToShopId从远程取数据
//改成call by name就没有这个问题啦
def cachedItemIdToShopId(itemId: Int, remoteShopId: =>Int): Int = {
cache.get(itemId) match {
case Some(shopId) => shopId
case None =>
val shopId = remoteShopId
cache += itemId -> shopId
shopId
}
}
//调用这个函数
cachedItemIdToShopId(itemId,itemIdToShopId(itemId))