1

这是我尽可能多地提炼出来的一些代码:

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
}
4

1 回答 1

2

简单的变量初始化顺序,从祖先开始。

首先, typeclassInVal在祖先特征被初始化。要做到这一点,requireTypeclass被称为。它在Bar和 access中被覆盖val typeclass,尚未初始化,因此此时为 null。所以typeclassInVal一劳永逸地初始化为null,并且在第一次使用它时会得到一个NPE。

简单的解决方法可能是没有 val,而只是祖先特征中的 def,或者有一个惰性 val。

于 2013-04-02T00:08:56.957 回答