在trait'之前调用类构造函数;scala中的s构造函数
我有这种情况在trait'之前调用类构造函数;scala中的s构造函数,scala,traits,Scala,Traits,我有这种情况 trait D { def someMethod(): Unit = {} } trait C { val locations: Seq[Int] someSomethingWithLocations() // calling this in constructor def someSomethingWithLocations(): Unit = { print(locations.length) } }
trait D {
def someMethod(): Unit = {}
}
trait C {
val locations: Seq[Int]
someSomethingWithLocations() // calling this in constructor
def someSomethingWithLocations(): Unit = {
print(locations.length)
}
}
class B extends D with C {
override val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
someMethod()
}
def main(args: Array[String]): Unit = {
val b = new B
}
当我运行这个代码somesomethinghithlocations
时,抛出空指针异常,因为还没有调用类B的构造函数,所以位置没有初始化。
如果我把B类的声明改为
class B extends{
override val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
someMethod()
} with D with C
编译器抱怨找不到someMethod()。我如何解决这个问题
现在,我已经将位置声明移到了一个不同的特性,我的程序按预期工作,但如果可能的话,我希望避免不必要的特性。您尝试的解决方案就是所谓的早期初始化器。您不能在其中调用
someMethod
,因为:
- 早期初始值设定项只能包含
定义val
- 包含
的traitsomeMethod
是在早期初始值设定项之后混合的,因此它还不能使用D
val
,不如尝试将其作为构造函数参数。调用任何构造函数代码之前,将初始化val
s的构造函数参数。在这里,您可以通过引入一个中间抽象类来实现:
abstract class AbstractB(val locations: Seq[Int])
class B extends AbstractB(1 :: 2 :: 3 :: Nil) with D with C {
someMethod()
}
val
成为lazy val
:
class B extends D with C {
override lazy val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
someMethod()
}
这样一来,位置
将不会在B类
的构造函数中初始化,而只是在首次访问时初始化,在您的情况下,这将是特质C的构造函数
(请注意,在这种情况下,lazy
关键字使字段比正常情况下更早而不是更晚初始化,这是关于lazy val
s的常见直觉)
lazy val
似乎是一个简单易行的解决方案,但如果可能的话,我建议首先尝试构造函数参数。这是因为lazy val
本身可能会访问另一个val
,而此时可能尚未初始化。这样,问题会升级到其他val
上,最终您可能会遇到问题发现自己不得不将它们全部声明为lazy
class B extends {
override val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
} with D with C {
someMethod()
}
您尝试的解决方案称为早期初始值设定项。您不能在其中调用
someMethod
,因为:
- 早期初始值设定项只能包含
定义val
- 包含
的traitsomeMethod
是在早期初始值设定项之后混合的,因此它还不能使用D
val
,不如尝试将其设置为构造函数参数。在调用任何构造函数代码之前,将初始化val
s构造函数参数。在这里,您可以通过引入中间抽象类来完成此操作:
abstract class AbstractB(val locations: Seq[Int])
class B extends AbstractB(1 :: 2 :: 3 :: Nil) with D with C {
someMethod()
}
val
成为lazy val
:
class B extends D with C {
override lazy val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
someMethod()
}
这样一来,位置
将不会在B类
的构造函数中初始化,而只是在首次访问时初始化,在您的情况下,这将是特质C的构造函数
(请注意,在这种情况下,lazy
关键字使字段比正常情况下更早而不是更晚初始化,这是关于lazy val
s的常见直觉)
lazy val
似乎是一个简单易行的解决方案,但如果可能的话,我建议首先尝试构造函数参数。这是因为lazy val
本身可能会访问另一个val
,而此时可能尚未初始化。这样,问题会升级到其他val
上,最终您可能会遇到问题发现自己不得不将它们全部声明为lazy
class B extends {
override val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
} with D with C {
someMethod()
}