267 votes

Que fait un val paresseux?

J'ai remarqué que Scala fournit lazy vals . Mais je ne comprends pas ce qu'ils font.

 scala> val x = 15
x: Int = 15

scala> lazy val y = 13
y: Int = <lazy>

scala> x
res0: Int = 15

scala> y
res1: Int = 13
 

Le REPL montre que y est un lazy val , mais en quoi est-il différent d'un val normal?

359voto

sschaef Points 20242

La différence entre eux est que, val est exécutée lorsqu'elle est définie alors qu'un lazy val est exécuté quand il est accédé à la première heure.

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

Contrairement à une méthode (défini avec def) lazy val est exécutée une fois et plus jamais ensuite. Cela peut être utile lorsqu'une opération prend du temps et quand il n'est pas sûr s'il est utilisé plus tard.

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

Ici, lorsque les valeurs x et y ne sont jamais utilisés, seulement x inutilement le gaspillage des ressources. Si nous supposons qu' y n'a pas d'effets secondaires et que nous ne savons pas combien de fois il est accessible (jamais, une fois, des milliers de fois), il est inutile de le déclarer comme def depuis nous ne voulons pas de l'exécuter plusieurs fois.

Si vous voulez savoir comment lazy vals sont mis en œuvre, voir cette question.

63voto

Landei Points 30509

Cette fonctionnalité permet non seulement de retarder les calculs coûteux, mais est également utile pour construire des structures dépendantes ou cycliques mutuelles. Par exemple, cela conduit à un débordement de pile:

 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
 

Mais avec des valses paresseuses ça marche bien

 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()
 

19voto

Jus12 Points 4580

Aussi lazy est utile sans dépendances cycliques, comme dans le code suivant:

 abstract class X {
  val x: String
  println ("x is "+x.length)
}

object Y extends X { val x = "Hello" }
Y
 

L'accès à Y lancera désormais une exception de pointeur nul, car x n'est pas encore initialisé. Ce qui suit fonctionne bien:

 abstract class X {
  val x: String
  println ("x is "+x.length)
}

object Y extends X { lazy val x = "Hello" }
Y
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X