在参数列表和初始值设定项列表中分配值之间的区别

iDe*_*ode 4 dart

class A {
  A(int value);
}

class B extends A{
  final int foo;

  B.one(this.foo) : super(foo); // Works

  B.two(int foo) : foo = foo, super(this.foo); // Doesn't work
}
Run Code Online (Sandbox Code Playgroud)

在 中B.one,我可以轻松地将 的值传递给footosuper但在 中B.two,我不能这样做。在这两种情况下,该字段foo都是在调用之前分配的super,在一种情况下它有效,在另一种情况下它失败。所以,问题是在构造函数中什么时候创建字段。

jam*_*lin 8

Dart 分两个阶段构造对象:首先是由外向内,然后是由内向外。

初始化列表是由外向内执行的(从派生类到基类)。完成此操作后,对象的成员应该被初始化,该对象被认为是“构造的”并且this存在。(这就是为什么你不能this在初始化列表中以有意义的方式使用;它还不存在。)(从技术上讲,直接成员初始化发生在初始化列表之前,但为了简单起见,我将它们集中在一起。)

然后构造函数主体从内到外执行(从基类到派生类)。

此方法保证在执行基类构造函数主体时初始化所有对象的成员,从而允许在构造函数主体中进行虚拟分派。(相比之下,C++ 完全由内而外地构造对象,并且不允许在构造函数和析构函数中进行虚拟分派。或者与 Python 相比,在 Python 中,类主要定义自己的构造顺序,并且类负责确保任何虚函数调用由构造函数执行是安全的。)

如果没有这种方法,Dart 构造函数体要么无法保证执行虚拟函数(Java 方法)时的安全性,要么必须禁止虚拟分派(C++ 方法)。

这种方法的一个结果是final变量可以通过初始化列表初始化,但不能通过构造函数体初始化:当构造函数体执行时,所有成员变量(不是late且不能为空)都应该已经初始化。

另请参阅: