懒惰的Val - 如何重置价值?

时间:2015-05-09 20:29:15

标签: scala lazy-evaluation

我可能想要使用昂贵的方法并根据副作用返回结果。例如,取决于一天/一周的时间和量子时间动力学的蒙特卡罗模拟。因为它很昂贵且我可能不需要它,所以我将使用Scalas lazy val

lazy val maybeUnusedValue = getDayOfWeek

现在我的程序仍在运行12小时。我想重做计算,因为我的日子可能在此期间发生了变化。

是否有一种简单的方法可以强制Scala将maybeUnusedValue恢复为未初始化状态,从而强制重新计算其下一次使用?

2 个答案:

答案 0 :(得分:7)

  

有一个简单的方法

由于“laziness”是用跟踪初始化的字段实现的,所以简单的解决方案是使用可变引用来包装lazy val。当然,你必须处理该引用的可变性。

scala> class V { lazy val v = System.currentTimeMillis }
defined class V

scala> @volatile var x = new V
x: V = V@77468bd9

scala> x.v
res0: Long = 1431212391127

scala> x.v
res1: Long = 1431212391127

scala> x = new V
x: V = V@28f67ac7

scala> x.v
res2: Long = 1431212407970

然后像

scala> import concurrent._, duration._, ExecutionContext.Implicits.global
import concurrent._
import duration._
import ExecutionContext.Implicits.global

scala> implicit class ex(val d: Deadline) extends AnyVal { def expiring(f: => Unit) =
     | Future(Await.ready(Promise().future, d.timeLeft)) onComplete (_ => f) }
defined class ex

scala> 10 seconds fromNow expiring { x = new V }

scala> x.v
res4: Long = 1431212407970

scala> x.v
res5: Long = 1431212407970

scala> x.v
res6: Long = 1431213010180

答案 1 :(得分:2)

您遇到两个问题:

  • val是不可变的,即初始化后无法更改
  • 即使您使用了var,也没有机制在一段时间后过期

我的建议是将getDayOfWeek转换为跟踪其他实例中当前值和状态的函数:

private var dayOfWeek: Option[Day] = None
private var lastEvaluated: Int = 0

def getDayOfWeek = dayOfWeek match {
  case None => expensiveGetDayOfWeek
  case Some(day) =>
    if (DateTime.now.getDayOfYear > lastEvaluated) expensiveGetDayOfWeek
    else day

}

private def expensiveGetDayOfWeek: Day = {
  dayOfWeek = Some(someExpensiveOperation())
  lastEvaluated = DateTime.now.getDayOfYear
  dayOfWeek.get
}

我的状态跟踪何时重新计算有点hacky,所以你想要自己想出来,但基本的要点是你按需计算。