2013年2月4日月曜日

[Scala] Lazy による遅延評価

変数宣言時に Lazy キーワードをつけるとその値が必要になるまで値の評価を遅延できる。
  var x = 1;
  lazy val z = x*2;
  x = 2;
  println(z);

--------------------
4
変数宣言時には x の値は 1 だが、println(z) 呼び出しで z の値が必要になった時点で評価されるので、 出力は 4 になる。


値解決のタイミング


名前渡しの場合には 値が必要なときには毎回式が評価されていた。
Lazy 変数の場合には、名前渡しと違って一時的に評価が遅延されているだけなので、一回評価されるとその時点で値が確定する。
  var x = 1;
  lazy val z = x*2;
  x = 2;
  println(z);
  x = 100;
  println(z);

--------------------
4
4
2回目の println(z) 呼び出し時には x=100 になっているが、すでに z の値は 4 で確定しているため再評価されることはない。

この性質は要注意で、デバッグ目的で不用意に値を出力するコードを追加すると式が評価されて値の確定するタイミングが変わるため、予期しない問題を引き起こすことになりそう。
  var x = 1;
  lazy val z = x*2;
  if (logger.isLoggable(Level.FINE))  logger.info("z=" + z);

  x = 2;
  println(z);  // 4
こんなコードがあるとログレベルを変えると結果が変わってしまい混乱するもとになる。


var 変数は lazy にできない。


lazy を付与できるのは val 変数だけで、var 変数に付与するとエラーになる。
scala> lazy var z = x;
<console>:1: error: lazy not allowed here. Only vals can be lazy
       lazy var z = x;
            ^


0 件のコメント:

コメントを投稿