除非打印,否则Scala :: lazy值为null?

jde*_*lop 5 scala nullpointerexception lazy-initialization

鉴于特点(简化)

trait A {
  val eventStream: EventStream
  val credentialsStorage = // something here
  val userStorage = // something here
  val crypto = // something here
  ...    
  lazy val authSvc = new CoreAuthentication(credentialsStorage, new AuthenticationProviderResolver, userStorage, eventStream, crypto)
}

class T extends A with TraitProvidingEventStream with FlatSpec with [lot of another traits here] {

  val eventStream = systemFromTraitProvidingEventStream.eventStream

  "This" should "work" in {
    println(authSvc) // this is "magic"
    val user = authSvc.doSomethingWithUser(...);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果我删除标记为//这是"魔术"的行,那么我将在下一行获得NullPointerException,因此authSvc为null.

那可能有什么问题?

我无法为此创建干净的小测试用例,通常这种方法效果很好

som*_*ytt 5

这在 ML 上出现过一次:如果在初始化惰性 val 时抛出异常,则 val 为 null;但是你可以尝试再次初始化,它可以神奇地工作。(也就是说,在第一次尝试初始化失败时不会设置惰性 val 的“已初始化”位标志。)

我认为 ML 上的情况与特征中 val 的 init 顺序有关,所以也许这就是您的问题。依赖它是臭名昭著的危险,因此建议在特征中使用 defs。参见 Luigi 对 DelayedInit 的评论。