Dart:为什么继承字段不能用作构造函数参数?
Dart: Why are inherited fields not usable as constructor arguments?
下面的代码不会运行:
class X{
double? x;
}
mixin Y{
double? y;
}
class Z extends X with Y {
double? z;
Z(this.x, this.y, this.z)
}
编译器会抱怨 this.x 和 this.y 不是封闭 class:
中的字段
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)
^
当然不是这样的,字段x和y是继承自parent class和mixin。我可以在子 class Z 中使用这些字段,似乎只有构造函数在接受这些作为参数时遇到问题。但是为什么?
Dart 实例变量(又名“字段”)引入一个存储单元、一个隐式 getter 和一个隐式 setter(除非变量是 final
而不是 late
,则没有setter).
构造函数初始化器可以直接初始化存储单元,无需调用setter,即使没有setter。这就是 Z(this.z)
或 Z(double? z) : this.z = z;
所做的,它将一个值直接存储到实例变量的存储中。
像 Z(double? z) { this.z = z; }
这样的构造函数不会直接存储到单元格中,而是调用名为 z=
的 setter 然后可能存储到(必须是非最终的或延迟的)变量的存储。
或者它可能不会。设置器是虚拟的,subclass 可以覆盖它们,{ this.z = z; }
赋值会调用被覆盖的 setter.
一般来说,subclass是看不到super[=40=的变量的,它看到的只是super[=]的接口 40=],它只公开 getter 和 setter。如果 superclass 决定将字段声明更改为 getter 和 setter 声明对,那么它们 可以 。它是不间断的,subclass 无法区分。
所以,如果 subclass 能以某种方式看到一个变量可以被 初始化(而不只是分配给),那么我们就打破了这种对称性,而 superclass 被锁定为具有可初始化变量。
初始化必须发生在声明实例变量 的 class 中,因为 如果没有,我们就会破坏 class 的抽象通过泄漏 getter/setter 是否由字段支持来实现接口,然后我们将 class 锁定到该选择中。这与 Dart 具有它所具有的那种 getter/setter 声明的原因完全相反,它使它成为一个实现选择,无论你使用一个还是另一个,而不是 public API 选择.
下面的代码不会运行:
class X{
double? x;
}
mixin Y{
double? y;
}
class Z extends X with Y {
double? z;
Z(this.x, this.y, this.z)
}
编译器会抱怨 this.x 和 this.y 不是封闭 class:
中的字段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)
^
当然不是这样的,字段x和y是继承自parent class和mixin。我可以在子 class Z 中使用这些字段,似乎只有构造函数在接受这些作为参数时遇到问题。但是为什么?
Dart 实例变量(又名“字段”)引入一个存储单元、一个隐式 getter 和一个隐式 setter(除非变量是 final
而不是 late
,则没有setter).
构造函数初始化器可以直接初始化存储单元,无需调用setter,即使没有setter。这就是 Z(this.z)
或 Z(double? z) : this.z = z;
所做的,它将一个值直接存储到实例变量的存储中。
像 Z(double? z) { this.z = z; }
这样的构造函数不会直接存储到单元格中,而是调用名为 z=
的 setter 然后可能存储到(必须是非最终的或延迟的)变量的存储。
或者它可能不会。设置器是虚拟的,subclass 可以覆盖它们,{ this.z = z; }
赋值会调用被覆盖的 setter.
一般来说,subclass是看不到super[=40=的变量的,它看到的只是super[=]的接口 40=],它只公开 getter 和 setter。如果 superclass 决定将字段声明更改为 getter 和 setter 声明对,那么它们 可以 。它是不间断的,subclass 无法区分。 所以,如果 subclass 能以某种方式看到一个变量可以被 初始化(而不只是分配给),那么我们就打破了这种对称性,而 superclass 被锁定为具有可初始化变量。
初始化必须发生在声明实例变量 的 class 中,因为 如果没有,我们就会破坏 class 的抽象通过泄漏 getter/setter 是否由字段支持来实现接口,然后我们将 class 锁定到该选择中。这与 Dart 具有它所具有的那种 getter/setter 声明的原因完全相反,它使它成为一个实现选择,无论你使用一个还是另一个,而不是 public API 选择.