以下是我尽可能多地提炼出的一些代码:
trait CakeLayer[A] extends {
// typeclass hack to make it play nice with traits
implicit def requireTypeclass: MyTypeclass[A]
val typeclassInVal = requireTypeclass
/* other stuff */
}
class FooImpl
object FooImpl {
implicit object FooImplIsTypeclass extends MyTypeclass[FooImpl]
}
// This works perfectly
class Foo extends CakeLayer[FooImpl] {
override def requireTypeclass = implicitly
}
// This gives me NullPointerException
// Occurs in a function of my "Bar" that contains an anonymous function
// which uses typeclassInVal. it is the first access to that val
// probably due to the parameter in the typeclass constructor?
class BarImpl(x: Int)
object BarImpl {
class BarImplIsTypeclass(x: Int) extends MyTypeclass[BarImpl]
}
class Bar(x: Int) extends CakeLayer[BarImpl] {
val typeclass = new BarImpl.BarImplIsTypeclass(x)
override def requireTypeclass = typeclass
}
答案 0 :(得分:2)
简单的变量初始化顺序,以祖先开头。
首先,初始化祖先特征中的typeclassInVal
。为此,调用requireTypeclass
。它在Bar
中被覆盖并且访问val typeclass
,尚未初始化,因此此时为null。所以typeclassInVal
被初始化为null,并且一劳永逸,并且在第一次使用它时会得到一个NPE。
简单的解决方法可能没有val,而只是祖先特征中的def,或者具有懒惰的val。