Dart中命名构造函数是否是生成构造函数的子集? [英] Are named constructors a subset of generative constructors in Dart?

查看:167
本文介绍了Dart中命名构造函数是否是生成构造函数的子集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Dart语言导览中,它为构造函数提供了一个示例生成构造函数:

  class Point {
double x,y;

点(双倍x,双倍y){
//有一种更好的方法,敬请期待。
this.x = x;
this.y = y;
}
}

稍后提供了命名构造函数

 类点{
double x,y;

点(this.x,this.y);

//命名构造函数
Point.origin(){
x = 0;
y = 0;
}
}

这使我相信,当构造函数使用与类,它是一个生成的构造函数:

  Point(this.x,this.y); 

但是当有其他标识符时,它是一个命名的构造函数:

  Point.origin(){
x = 0;
y = 0;
}

但是,在另一个我的答案 Dart专家更改了我对命名构造函数的措辞,到生成构造函数。这使我意识到我可能误解了两者之间的区别。命名构造函数是生成构造函数的子集吗?如果是这样,我该如何调用仅具有类名称但不附加其他标识符的构造函数?


术语命名构造函数 语言规范中似乎没有。

解决方案

在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); //生成的,未命名的,非转发的const。
const Point.diagonal(double xy):this(xy,xy); //生成,命名,转发,常量。
}

转发工厂构造函数将其参数转发给其他构造函数。示例:

 抽象类Point {
double get x;
双倍获得y;
const factory Point(this.x,this.y)= _Point; //工厂,未命名,转发,常量。
}
类_Point实现Point {
final double x,y;
const _Point(this.x,this.y); //生成的,未命名的,非转发的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 构造函数)。 / p>

In the Dart language tour for constructors it gives an example of a generative constructor:

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;
  }
}

Later it gives an example of a named constructor:

class Point {
  double x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

That led me to believe that when a constructor uses the same name as a class it is a generative constructor:

Point(this.x, this.y);

But when there is an additional identifier then it is a named constructor:

Point.origin() {
  x = 0;
  y = 0;
}

However, on another one of my answers a Dart expert changed my wording of "named constructor" to "generative constructor". That made me realize that I may have misunderstood the difference between them. Is a named constructor a subset of a generative constructor? If so, how do I call a constructor that only has the name of the class without an additional identifier attached?

The term "named constructor" doesn't appear to be in the language spec.

解决方案

In Dart any constructor is either a generative constructor or a factory constructor. If it says factory in front, it's a factory constructor, otherwise it's a generative constructor.

A generative constructor always creates a new instance of the precise class it belongs to. A factory constructor is (almost) just a static function with a return type which is the type of the class it belongs to. It can return any subtype of that, but it doesn't create any new objects by itself.

Constructors can be named or unnamed. For the class Foo, the constructor named Foo is the "unnamed" (or, really, "empty-named") constructor, and Foo.someName is a named constructor. Whether a constructor is named or unnamed is independent of whether it's generative or a factory. Dart doesn't have overloading (multiple declarations with the same name in the same scope, typically distinguished by the argument types), so without named constructors, it would only be possible to have one constructor per class. Named constructors allows a class to have as many constructors as it wants to, and each one can be any of the variations of constructors that the language allows.

Constructors can be either forwarding or, for lack of a better name, non-forwarding. A forwarding generative constructor must forward to a generative constructor of the same class. Example:

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.
}

A forwarding factory constructor forwards its parameters to a different constructor. Example:

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.
}

The two kinds of forwarding constructors, generative and factory, are not really related. They work in quite different ways, but both delegate the job of returning the object to another constructor, and they cannot have a body. Again, being named is independent of all of this.

Finally, constructors can be const or not. A const generative constructor is either forwarding to another const generative constructor, and the : this(...) arguments must be potentially constant expressions, or it's non-forwarding, and then all initializer expressions must be potentially constant expressions and there cannot be a body. A const factory constructor must be forwarding to another const constructor (whether factory or generative). Const constructors cannot have a body, and non-forwarding factory constructors must have a body.

Of all these different constructors, only the non-forwarding generative constructor can actually create a new object itself. That's where the real action happens. That's the most fundamental constructor, and it can look something like:

  Foo.bar(this.value, int otherValue) : _otherValue = otherValue, super.bar(42) {
    this.doSomething();
  }

A non-redirecting factory constructor is the only place you can use initializing formals (the parameter of the form this.value). The initializer list can initialize instance variables declared in the same class, but can obviously be empty if there are none. The super-invocation at the end must call a generative constructor of the superclass, but defaults to super() if omitted. The body is the first place the new object becomes available (as this), but the body can be omitted (replaced by ;) if it's empty. That's why the simplest constructor is just Foo(); (which is also the default constructor that you get if you declare no other constructor).

这篇关于Dart中命名构造函数是否是生成构造函数的子集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆