根据我们在方法 scala 中获得的值实例化顶级惰性值

Instantiate a top level lazy value based on value we get in a method scala

有没有办法根据我们在方法中获得的值来实例化顶级惰性值

trait Props {
  val env: String
}

object Exc extends App {
  Foo.getInput("dev")
}

object Foo extends Props {

  lazy val env: String = ???
  
  def getInput(e: String): Unit = {
    //How do I instantiate env with e here
    env = e //this doesn't work
  }

  def exampleMethod() = println(env)
}

object Foo 必须扩展 trait Props,所以我需要根据方法中传递的内容找出一种方法来实例化变量 env

在这种情况下 env 应该是 var:

var env: String = ???

lazy这里不需要

最接近您想要的可能是 Future,这是语言和标准库中的另一个值得注意的情况,在这种情况下可以延迟求值并且结果是一次写入。

所以像下面这样

import scala.concurrent.{ Await, Future, Promise }
import scala.concurrent.duration.Duration

object Foo extends Props {
  private val envPromise = Promise[String]()

  lazy val env: String = Await.result(envPromise.future, Duration.Inf)

  def getInput(e: String): Unit = {
    envPromise.success(e)
  }
}

如果在调用 getInput 之前访问了 env,它将阻塞访问线程任意长的时间,直到其他线程调用 getInput(如果没有其他线程调用,它实际上是无限循环)。或者,可以在 Await 上放置一个有限的持续时间(例如 3.minutes),如果在那段时间没有调用 getInput,这将抛出异常。 lazy 初始化器中的异常将传播到访问线程(这可能有点令人惊讶:给定 Props 的人会合理地期望访问 envval) 不会爆炸),但调用 getInput 后的后续访问将具有值。

多次调用 getInput 会抛出异常,因为 Promise 最多只能完成一次。

我的诚实意见是,可能值得重新审视导致这种情况的决定。我会特别考虑一些替代方案,例如:

object Foo {
  private val propsPromise = Promise[Props]()

  val propsFuture: Future[Props] = propsPromise.future

  def getInput(e: String): Unit =
    propsPromise.success(new Props { val env: String = e })
}

您正在延迟构造一个有效的 Props 实例,但可以静态地提供对该实例的引用,因为 if/when 它存在。