Phi*_*ipp 5 inheritance mixins dart
以下代码将不会运行:
class X{
double? x;
}
mixin Y{
double? y;
}
class Z extends X with Y {
double? z;
Z(this.x, this.y, this.z)
}
Run Code Online (Sandbox Code Playgroud)
编译器会抱怨 this.x 和 this.y 不是封闭类中的字段:
lib/physicalObject.dart:20:10: Error: 'x' isn't an instance field of this class.
Z(this.x, this.y, this.z)
^
lib/physicalObject.dart:20:18: Error: 'y' isn't an instance field of this class.
Z(this.x, this.y, this.z)
^
Run Code Online (Sandbox Code Playgroud)
当然这不是真的,字段x和y是从父类和mixin继承的。我可以在子类 Z 中使用这些字段,似乎只有构造函数在接受这些字段作为参数时存在问题。但为什么?
Dart 实例变量(又名“字段”)引入了一个存储单元、一个隐式 getter 和一个隐式 setter(除非变量 isfinal且 not late,则没有 setter)。
构造函数初始化器可以直接初始化存储单元,而不需要调用setter,即使没有setter。这就是Z(this.z)or 的Z(double? z) : this.z = z;作用,它将一个值直接存储到实例变量的存储中。
像这样的构造函数Z(double? z) { this.z = z; }不会直接存储到单元格中,而是调用名为的 setter,z=然后该 setter 可能会存储到(必然是非最终或晚期)变量的存储中。或者也可能不会。Setter 是虚拟的,子类可以覆盖它们,并且赋值{ this.z = z; }将调用被覆盖的 Setter。
一般来说,子类看不到超类的变量,它看到的只是超类的接口,该接口仅公开 getter 和 setter。如果超类决定将字段声明更改为 getter 和 setter 声明对,那么他们就可以。它是非破坏性的,子类无法区分。因此,如果子类可以以某种方式看到变量可以被初始化(而不仅仅是分配),那么我们就打破了这种对称性,并且超类被锁定为具有可初始化的变量。
初始化必须在声明实例变量的类中进行,因为如果没有,我们就会通过泄漏 getter/setter 是否由字段支持来破坏该类接口的抽象,然后我们将类锁定到该选择中。这与 Dart 具有 getter/setter 声明的原因完全相反,无论您使用其中一种还是另一种,它都是一种实现选择,而不是公共 API 选择。