在异常情况下,`lazy val` 的行为类似于 `def` 是正确的行为吗? [英] Is it correct behaviour that `lazy val` acts like `def` in case of exception?

查看:55
本文介绍了在异常情况下,`lazy val` 的行为类似于 `def` 是正确的行为吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到 lazy val 多次重复计算(以防万一):

I've noticed that lazy val repeats computation several times (in case of exception):

scala> lazy val aaa = {println("calc"); sys.error("aaaa")}
aaa: Nothing = <lazy>

scala> aaa
calc
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at .aaa$lzycompute(<console>:7)
  at .aaa(<console>:7)
  ... 33 elided

scala> aaa
calc
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at .aaa$lzycompute(<console>:7)
  at .aaa(<console>:7)
  ... 33 elided

不应该是这样的:

scala> aaa
calc
java.lang.RuntimeException: Not Initialized! 
caused by
java.lang.RuntimeException: aaaa

scala> aaa
java.lang.RuntimeException: Not Initialized! 
caused by
java.lang.RuntimeException: aaaa  

推荐答案

this 文章很好地解释了 lazy val 是如何被 Scala 编译器编译的.基本上,如果表达式的评估失败,则不会设置指示 lazy val 包含其数据的指示符位.

In this post they explain very well how lazy val is compiled by the Scala compiler. Basically, if the evaluation of the expression fails, then the indicator-bit signaling that the lazy val contains its data won't be set.

更新 1:

我认为采用第一种方法的一个原因可能是第二种方法可以通过使用两个 lazy val 来模拟,而不会给底层实现带来多个 volatile 变量的负担:

I think one reason going with the first approach could be that the second one may be emulated by using two lazy vals, without burdening the underlying implementation with multiple volatile variables:

scala> lazy val _aaa = Try {println("calc"); sys.error("aaaa")}
_aaa: scala.util.Try[Nothing] = <lazy>

scala> lazy val aaa = _aaa.get
aaa: Nothing = <lazy>

scala> aaa
calc
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at $anonfun$_aaa$1.apply(<console>:10)
  at $anonfun$_aaa$1.apply(<console>:10)
  at scala.util.Try$.apply(Try.scala:191)
  at ._aaa$lzycompute(<console>:10)
  at ._aaa(<console>:10)
  at .aaa$lzycompute(<console>:11)
  at .aaa(<console>:11)
  ... 33 elided

scala> aaa
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at $anonfun$_aaa$1.apply(<console>:10)
  at $anonfun$_aaa$1.apply(<console>:10)
  at scala.util.Try$.apply(Try.scala:191)
  at ._aaa$lzycompute(<console>:10)
  at ._aaa(<console>:10)
  at .aaa$lzycompute(<console>:11)
  at .aaa(<console>:11)
  ... 33 elided

更新 2:

正如 @Silly Freak 在评论中提出的那样,

As @Silly Freak has proposed in his comment,

scala> lazy val _aaa = Try {println("calc"); sys.error("aaaa")}
_aaa: scala.util.Try[Nothing] = <lazy>

scala> def aaa = _aaa.get
aaa: Nothing

可能会更好,因为我们可以避免有两个 lazy val.

may work even better, as we can avoid having two lazy vals.

这篇关于在异常情况下,`lazy val` 的行为类似于 `def` 是正确的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆