【问题标题】:Are named constructors a subset of generative constructors in Dart?命名构造函数是 Dart 中生成构造函数的子集吗?
【发布时间】:2020-08-08 08:02:31
【问题描述】:

在构造函数的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 中似乎没有术语“命名构造函数”。

【问题讨论】:

  • 规范实际上做了mention“命名构造函数”,它只是没有指定它。规范没有区分,它只是说构造函数的名称要么是类名,要么是类名,后跟一个. 和一个标识符。短语“命名构造函数”通俗地用于那些名称带有尾随标识符的构造函数,因为它比“具有......某物的名称的构造函数”更容易说出来。

标签: dart constructor


【解决方案1】:

在 Dart 中,任何构造函数要么是 generation 构造函数,要么是 factory 构造函数。 如果前面写着factory,则为工厂构造函数,否则为生成构造函数。

生成式构造函数总是创建它所属的精确类的 new 实例。 工厂构造函数(几乎)只是一个静态函数,其返回类型是它所属的类的类型。它可以返回它的任何子类型,但它本身不会创建任何新对象。

构造函数可以是命名的未命名的。对于Foo 类,名为Foo 的构造函数是“未命名”(或者,实际上是“空命名”)构造函数,而Foo.someName 是命名构造函数。构造函数是命名还是未命名与它是生成式还是工厂无关。 Dart 没有重载(在同一范围内有多个同名声明,通常由参数类型区分),因此如果没有命名构造函数,每个类只能有一个构造函数。命名构造函数允许一个类拥有任意数量的构造函数,并且每个构造函数都可以是语言允许的构造函数的任何变体。

构造函数可以是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 构造函数)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 2023-03-15
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    相关资源
    最近更新 更多