Scala 专题教程-抽象成员(4): 预先初始化成员的值

jerry Scala 2015年11月25日 收藏

为了解决上篇中RationalTrait 的问题,有两个解决方案,第一方案是使用预先初始化成员的值的方法,这种方法可以让你在调用父类构造函数之前首先初始化子类的成员。
这种方法,是把初始化成员变量的定义放在调用父构造函数之前。

下面是一个匿名实例化Trait的例子

  1. val x = 1
  2.  
  3. new {
  4. val numerArg =1 * x
  5. val denomArg = 2 *x
  6. } with RationalTrait
  7.  
  8. res1: RationalTrait = 1/2

可以看到在这个例子中,我们把初始化成员的代码放在其父Trait之前。 再看一个例子:

  1. object twoThirds extends {
  2. val numerArg =1 * x
  3. val denomArg = 2 *x
  4. } with RationalTrait
  5.  
  6. defined object twoThirds
  7.  

初始化成员部分也是防止其父Trait之前,两个方法都使用with。

这种方法除了可以应用中匿名实例和对象外,也可以应用中类的定义说,比如我们可以定义如下的RationalClass

  1. class RationalClass(n:Int,d:Int) extends {
  2. val numerArg =n
  3. val denomArg =d
  4. } with RationalTrait {
  5. def + (that: RationalClass) = new RationalClass(
  6. numer * that.denom + that.numer * denom,
  7. denom * that.denom
  8. )
  9. }
  10.  

因为这些预先初始化的值发生在调用父类的构造函数之前,因此这些初始化这些值时不可以引用正在构造的对象,正因为如此,如果在初始化的表达式中使用this,这个this不是指正在构造的对象,而是指包含这个定义的对象。比如:

  1. new {
  2. val numberArg =1
  3. val denomArg = this.numerArg *2
  4. } with RationalTrait
  5.  
  6. <console>:11: error: value numerArg is not a member of object $iw
  7. val denomArg = this.numerArg *2
  8.  

这个例子无法编译,这是因为编译器无法找到 对象$iw的numerArg 成员,$iw 为Scala命令行输入的当前对象。