在 Dart 中,initializer lists 是构造函数的一种特性,允许你在进入构造函数体之前对某些字段进行初始化或进行检查。这些字段包括 final 字段,因为 final 字段必须在构造函数体运行之前被初始化。
以下是它的几个关键点和适用场景:
1. 什么是 Initializer List?
Initializer list 是写在构造函数签名后但在构造函数体之前的代码部分,用冒号 : 引导,多个表达式用逗号 , 分隔。
语法结构:
ClassName.constructorName(parameters): field1 = value1,field2 = value2 {// 构造函数体
}
在这里,field1 = value1
和 field2 = value2
就是初始化列表的一部分,它们在构造函数体运行之前被执行。
2. 为什么需要 Initializer List?
- 初始化 final 字段
- final 字段在 Dart 中只能赋值一次,因此必须在构造函数体执行前完成初始化。
- Initializer list 是给这些字段赋值的唯一地方。
- 提前运行一些逻辑
- 你可能希望在进入构造函数体之前,完成某些逻辑,比如参数验证或初始化值。
- 父类构造函数调用(超类字段初始化)
- 如果当前类继承了某个父类,super 调用也必须写在初始化列表中。
3. 代码示例
例子 1:初始化 final 字段
class Point {final double x;final double y;// 使用初始化列表Point(this.x, this.y);
}
例子 2:使用初始化列表进行字段初始化
class Point {final double x;final double y;// 从 JSON 数据中提取 x 和 y 的值Point.fromJson(Map<String, double> json): x = json['x']!,y = json['y']! {print('Created a Point: ($x, $y)');}
}
- 过程说明:
- 在进入 {} 中的构造函数体之前,x 和 y 就被赋值为 json[‘x’] 和 json[‘y’]。
- 如果没有使用 initializer list,像这样的 final 字段会因为未初始化而导致编译错误。
例子 3:添加断言
断言是调试中用来检查条件的方式,只在开发环境中运行(生产环境中会被移除)。
class NonNegativePoint {final double x;final double y;NonNegativePoint(this.x, this.y): assert(x >= 0),assert(y >= 0) {print('Created NonNegativePoint: ($x, $y)');}
}
- 过程说明:
- 如果 x 或 y 是负数,断言会抛出一个错误。
- 断言代码写在 initializer list 中,保证在构造函数执行之前验证。
例子 4:调用父类构造函数
class A {A(String name) {print('A\'s constructor: $name');}
}class B extends A {final int age;B(String name, this.age): super(name) { // 调用父类的构造函数print('B\'s constructor: $name, $age');}
}
- 过程说明:
- B 的构造函数在执行之前调用了 A 的构造函数 super(name),确保父类的初始化。
4. 注意事项
- 字段顺序
- Initializer list 中的字段初始化顺序与它们在类定义中的声明顺序一致,而不是写在 initializer list 中的顺序。
- 避免调用 this
- 在初始化列表中,不能使用 this,因为对象还未完全初始化。
总结
Initializer list 主要用来在构造函数体执行之前完成:
- 初始化 final 字段
- 运行前置逻辑(如断言检查)
- 调用父类构造函数
它是一种简洁而安全的方式来确保对象在构造时的正确性。