在Dart language tour中的构造函数中,给出了一个生成构造函数的示例:
class Point {
double x, y;
Point(double x, double y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
}
稍后提供了named constructor的示例:
class Point {
double x, y;
Point(this.x, this.y);
// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}
这使我相信,当构造函数使用与类相同的名称时,它就是生成的构造函数:
Point(this.x, this.y);
但是,当有一个附加标识符时,它就是一个命名构造函数:
Point.origin() {
x = 0;
y = 0;
}
但是,在my answers的另一位专家中,Dart专家将我的“命名构造函数”的措词改为了“生成构造函数”。这使我意识到我可能误解了两者之间的区别。命名构造函数是生成构造函数的子集吗?如果是这样,我该如何调用仅具有类名称而没有附加标识符的构造函数?
“命名构造函数”一词似乎不在language spec中。
答案 0 :(得分:10)
在Dart中,任何构造函数都是 generative 构造函数或 factory 构造函数。
如果在前面说factory
,则是工厂构造函数,否则是生成构造函数。
生成式构造函数总是创建其所属的精确类的 new 实例。 工厂构造函数(几乎)只是一个静态函数,其返回类型为它所属的类的类型。它可以返回该类型的任何子类型,但是它本身不会创建任何新对象。
构造函数可以命名或未命名。对于类Foo
,名为Foo
的构造函数是“未命名”(或实际上是“空命名”)的构造函数,而Foo.someName
是命名的构造函数。构造器是命名的还是未命名的与生成器或工厂无关。
Dart没有 overloading (在同一范围内具有相同名称的多个声明,通常由参数类型区分),因此,如果没有命名构造函数,则每个类只能有一个构造函数。命名构造函数允许一个类拥有所需数量的构造函数,并且每个构造函数可以是该语言允许的任何构造函数变体。
构造函数可以是 forwarding ,也可以是 non-forwarding ,但缺少更好的名称。 转发生成生成器必须转发到同一类的生成生成器。示例:
class Point {
final double x, y;
const Point(this.x, this.y); // Generative, unnamed, non-forwarding, const.
const Point.diagonal(double xy) : this(xy, xy); // Generative, named, forwarding, const.
}
转发工厂构造函数将其参数转发给其他构造函数。示例:
abstract class Point {
double get x;
double get y;
const factory Point(this.x, this.y) = _Point; // Factory, unnamed, forwarding, const.
}
class _Point implements Point {
final double x, y;
const _Point(this.x, this.y); // Generative, unnamed, non-forwarding, const.
}
这两种转发构造函数,生成的和工厂的,并没有真正的联系。它们以完全不同的方式工作,但是都委托将对象返回给另一个构造函数的工作,并且它们不能具有主体。同样,被命名与所有这些都无关。
最后,构造函数可以为const
,也可以不是。
const生成构造函数将转发到另一个const生成构造函数,并且: this(...)
参数必须是潜在的常量表达式,或者它是非转发的,然后所有初始化程序表达式都必须是潜在的常量表达式,并且不能有主体。
const工厂构造函数必须转发到另一个const构造函数(无论工厂还是生成)。 const构造函数不能具有主体,非转发工厂构造函数必须具有主体。
在所有这些不同的构造函数中,只有非转发的生成构造函数实际上可以自己创建一个新对象。这就是真正的动作发生的地方。那是最基本的构造函数,看起来可能像这样:
Foo.bar(this.value, int otherValue) : _otherValue = otherValue, super.bar(42) {
this.doSomething();
}
唯一可使用非重定向工厂构造函数的地方初始化形式化函数(格式为this.value
的参数)。初始化程序列表可以初始化在同一类中声明的实例变量,但是如果没有,则显然可以为空。最后,超级调用必须调用超类的生成构造函数,但是如果省略,则默认为super()
。正文是新对象可用的第一个位置(如this
),但是如果该对象为空,则可以省略(用;
代替)。这就是为什么最简单的构造函数只是Foo();
(如果不声明其他构造函数,它也是 default 构造函数的原因)。