Scala懒惰的瓦尔
例子
lazyval是一种语言功能,其中a的初始化val会延迟到首次访问它之前。此后,它的作用就像常规的val。
要使用它,请lazy在之前添加关键字val。例如,使用REPL:
scala> lazy val foo = { | println("Initializing") | "my foo value" | } foo: String = <lazy> scala> val bar = { | println("Initializing bar") | "my bar value" | } Initializing bar bar: String = my bar value scala> foo Initializing res3: String = my foo value scala> bar res4: String = my bar value scala> foo res5: String = my foo value
本示例演示了执行顺序。当lazyval被宣布,被保存到所有的foo值是一个懒惰的函数调用尚未评估。val设置常规后,我们会看到该println调用已执行,并且该值已分配给bar。当我们foo第一次println评估时,我们看到执行-但是在第二次评估时却没有。同样,当bar被评估时,我们看不到println执行-仅在声明时执行。
何时使用“懒惰”
初始化在计算上是昂贵的,并且val很少使用。
lazyvaltiresomeValue={(1to1000000).filter(x=>x%113==0).sum}
if(scala.util.Random.nextInt>1000){
println(tiresomeValue)
}
tiresomeValue需要很长时间才能计算出来,而且并不总是使用它。使其lazyval节省不必要的计算。
解决循环依赖
让我们看一个示例,其中在实例化期间需要同时声明两个对象:
objectcomicBook{
defmain(args:Array[String]):Unit={
gotham.hero.talk()
gotham.villain.talk()
}
}
classSuperhero(valname:String){
lazyvaltoLockUp=gotham.villain
deftalk():Unit={
println(s"Iwon'tletyouwin${toLockUp.name}!")
}
}
classSupervillain(valname:String){
lazyvaltoKill=gotham.hero
deftalk():Unit={
println(s"LetmeloosenupGothamalittlebit${toKill.name}!")
}
}
objectgotham{
valhero:Superhero=newSuperhero("Batman")
valvillain:Supervillain=newSupervillain("Joker")
}
如果没有关键字lazy,则各个对象不能成为对象的成员。执行这样的程序会导致程序错误java.lang.NullPointerException。通过使用lazy,可以在初始化引用之前对其进行分配,而不必担心具有未初始化的值。