【问题标题】:Call class contructor before trait's constructor in scala在scala中的特征构造函数之前调用类构造函数
【发布时间】:2017-02-05 13:38:58
【问题描述】:

我有这种情况

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
  }

当我运行此代码时,someSomethingWithLocations 抛出空指针异常,因为尚未调用 B 类的构造函数,因此未初始化位置。 如果我将 B 类的声明更改为

      class B extends{
        override val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
        someMethod()
      } with D with C 

编译器抱怨找不到 someMethod()。我该如何解决这个问题?

现在我已将位置声明移至不同的特征,我的程序按预期工作,但我想尽可能避免不必要的特征。

【问题讨论】:

    标签: scala traits


    【解决方案1】:

    您尝试的解决方案是所谓的早期初始化程序。你不能在里面调用someMethod,因为:

    • 早期初始化器只能包含 val 定义
    • 包含someMethod 的特征D 混合在早期初始化器之后,所以它还不能使用

    但无论如何,在修复初始化顺序时,应将早期初始化程序视为最后的手段。在回到它之前,您应该先尝试一些不那么 hacky 的解决方案:

    1. 不要从 trait 定义或覆盖 val,而是尝试将其设为构造函数参数。 vals 的构造函数参数在调用任何构造函数代码之前被初始化。在这里你可以通过引入一个中间抽象类来做到这一点:

      abstract class AbstractB(val locations: Seq[Int])
      class B extends AbstractB(1 :: 2 :: 3 :: Nil) with D with C {
        someMethod()
      }
      
    2. 将您的val 设为lazy val

      class B extends D with C {
        override lazy val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
        someMethod()
      }
      

      这种方式 locations 将不会在 class B 的构造函数中初始化,而只是在第一次访问时初始化,在您的情况下将是 trait C 的构造函数(请注意,在这种情况下,lazy 关键字使字段被初始化更早而不是更晚,这是关于lazy vals的常见直觉)。

      lazy val 似乎是一个简单易行的解决方案,但如果可能,我建议先尝试构造函数参数。这是因为lazy val 本身可能会访问另一个val,此时可能尚未初始化。这样问题就会升级到其他vals,最后你可能会发现自己必须将它们全部声明为lazy

    3. 如果你还想使用一个早期的初始化器,你需要把方法调用移到它之外,并把它放到构造器中:

      class B extends {
        override val locations: Seq[Int] = 1 :: 2 :: 3 :: Nil
      } with D with C {
        someMethod()
      }
      

    【讨论】:

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