【问题标题】:Scala :: lazy value is null unless printed?Scala :: 惰性值是 null 除非打印?
【发布时间】:2012-11-24 14:58:28
【问题描述】:

给定特征(简化)

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(...);
  }
}

如果我删除标记为 //this is "magic" 的行,那么我将在下一行得到 NullPointerException,因此 authSvc 为 null。

那里可能有什么问题?

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

【问题讨论】:

  • 您确定访问authSvc 会引发NPE,而不是doSomethingWithUser 方法或其参数吗?
  • 绝对是,即使它会在 doSomethingWithUser 内的某个地方抛出 NPE - 然后 println 对此没有任何作用。
  • 我想调试这个,但不知道如何。任何帮助将不胜感激。
  • 我怀疑这与 DelayedInit 特征混入您的 T 类有关。您应该尝试使示例真正最小化,以准确查看错误所在。
  • 问题是我无法真正缩小范围,它在我尝试的所有情况下都按预期工作,但原始来源。所以我想知道如何调试它 - 可能是 scala 编译器中的一些错误?

标签: scala nullpointerexception lazy-initialization


【解决方案1】:

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

我认为 ML 上的案例与特征中 val 的 init 顺序有关,所以也许这就是你的问题。依赖它是出了名的危险,因此建议在特征中使用 defs。请参阅 Luigi 对 DelayedInit 的评论。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多