Yanıtlar:
Aralarındaki fark, a val
tanımlandığında lazy val
yürütülürken, a ilk kez erişildiğinde yürütülür.
scala> val x = { println("x"); 15 }
x
x: Int = 15
scala> lazy val y = { println("y"); 13 }
y: Int = <lazy>
scala> x
res2: Int = 15
scala> y
y
res3: Int = 13
scala> y
res4: Int = 13
Bir yöntemin aksine (ile tanımlanır def
) a bir lazy val
kez ve daha sonra bir daha yürütülür. Bu, bir işlemin tamamlanması uzun zaman aldığında ve daha sonra kullanılıp kullanılmadığından emin olmadığında yararlı olabilir.
scala> class X { val x = { Thread.sleep(2000); 15 } }
defined class X
scala> class Y { lazy val y = { Thread.sleep(2000); 13 } }
defined class Y
scala> new X
res5: X = X@262505b7 // we have to wait two seconds to the result
scala> new Y
res6: Y = Y@1555bd22 // this appears immediately
Burada, değerler x
ve y
asla kullanılmadığında, sadece x
gereksiz yere kaynakları boşa harcar. Bunun y
herhangi bir yan etkisi olmadığını ve ne sıklıkta erişildiğini bilmediğimizi varsayarsak (asla, bir kez, binlerce kez), def
bunu birkaç kez yürütmek istemediğimiz için ilan etmek işe yaramaz .
Nasıl lazy vals
uygulandığını bilmek istiyorsanız , bu soruya bakın .
Lazy<T>
.NET ile karşılaştır
Bu özellik sadece pahalı hesaplamaları geciktirmekle kalmaz, aynı zamanda karşılıklı bağımlı veya döngüsel yapılar oluşturmak için de yararlıdır. Örneğin, bu bir yığın taşmasına yol açar:
trait Foo { val foo: Foo }
case class Fee extends Foo { val foo = Faa() }
case class Faa extends Foo { val foo = Fee() }
println(Fee().foo)
//StackOverflowException
Ancak tembel vals ile iyi çalışıyor
trait Foo { val foo: Foo }
case class Fee extends Foo { lazy val foo = Faa() }
case class Faa extends Foo { lazy val foo = Fee() }
println(Fee().foo)
//Faa()
Cevabın verildiğini anlıyorum ama benim gibi yeni başlayanlar için anlaşılmasını kolaylaştırmak için basit bir örnek yazdım:
var x = { println("x"); 15 }
lazy val y = { println("y"); x+1 }
println("-----")
x = 17
println("y is: " + y)
Yukarıdaki kodun çıktısı:
x
-----
y
y is: 18
Görülebileceği gibi, x başlatıldığında yazdırılır, ancak y aynı şekilde başlatıldığında yazdırılmaz (x'i burada kasten değişken olarak aldım - y başlatıldığında açıklamak için). Daha sonra y çağrıldığında, başlatılır ve son 'x' değeri dikkate alınır, ancak eskisi değil.
Bu yardımcı olur umarım.
Tembel bir val en kolay şekilde " memoized (no-arg) def" olarak anlaşılır .
Bir def gibi, tembel bir val çağrılıncaya kadar değerlendirilmez. Ancak sonuç kaydedilir, sonraki çağrılar kaydedilen değeri döndürür. Notlanan sonuç, veri yapınızda bir val gibi yer kaplar.
Diğerlerinin de belirttiği gibi, tembel bir val için kullanım durumları, pahalı hesaplamaları gerekene kadar ertelemek ve sonuçlarını saklamak ve değerler arasındaki belirli dairesel bağımlılıkları çözmek içindir.
Tembel vallar aslında az ya da çok kaydedilmiş defs olarak uygulanır. Uygulamalarının ayrıntılarını buradan okuyabilirsiniz:
http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html
Ayrıca lazy
şu kodda olduğu gibi, siklik bağımlılıklar olmadan yararlıdır:
abstract class X {
val x: String
println ("x is "+x.length)
}
object Y extends X { val x = "Hello" }
Y
Henüz başlatılmadığından erişim Y
artık boş gösterici istisnası atacak x
. Bununla birlikte, aşağıdakiler iyi çalışır:
abstract class X {
val x: String
println ("x is "+x.length)
}
object Y extends X { lazy val x = "Hello" }
Y
EDIT: aşağıdakiler de çalışır:
object Y extends { val x = "Hello" } with X
Buna "erken başlatıcı" denir. Daha fazla ayrıntı için bu SO sorusuna bakın.
Bir gösteri lazy
- yukarıda tanımlandığı gibi - çalıştırma vs tanımlanan zaman erişildiğinde yürütülmesi: (2.12.7 Scala kabuk kullanılarak)
// compiler says this is ok when it is lazy
scala> lazy val t: Int = t
t: Int = <lazy>
//however when executed, t recursively calls itself, and causes a StackOverflowError
scala> t
java.lang.StackOverflowError
...
// when the t is initialized to itself un-lazily, the compiler warns you of the recursive call
scala> val t: Int = t
<console>:12: warning: value t does nothing other than call itself recursively
val t: Int = t
scala> lazy val lazyEight = {
| println("I am lazy !")
| 8
| }
lazyEight: Int = <lazy>
scala> lazyEight
I am lazy !
res1: Int = 8