变量
下面的示例代码创建一个变量并将其初始化:
// 建议通过 var 声明局部变量而非使用指定的类型
var name = 'Bob';
变量仅存储对象的引用。这里名为 name 的变量存储了一个 String 类型对象的引用,“Bob” 则是该对象的值。
name
变量的类型被推断为String
,但是你可以为其指定类型。如果一个对象的引用不局限于单一的类型,可以将其指定为Object
(或dynamic
)类型。
// 任意类型
Object name = 'Bob';
// 指定类型
String name = 'Bob';
默认值
在 Dart 中,未初始化以及可空类型的变量拥有一个默认的初始值null
。(如果你未迁移至空安全,所有变量都为可空类型。)即便数字也是如此,因为在 Dart 中一切皆为对象,数字也不例外。
int? lineCount;
// assert() 的调用将会在生产环境的代码中被忽略掉。在开发过程中,assert(condition) 会在条件判断为 false 时抛出一个异常。
assert(lineCount == null);
如果你启用了空安全,则必须在使用一个非空变量前为其进行初始化赋值:
int lineCount = 0;
在声明一个局部变量时就为其赋值不是必须的,但你需要在使用这个变量之前为其赋值。例如,以下代码是有效的,因为 Dart 能检测到lineCount
在被作为参数传递到print()
函数时是非空的。
int lineCount;
if (weLikeToCount) {
lineCount = countLines();
} else {
lineCount = 0;
}
print(lineCount);
Late variables
Dart 2.12 新增了late
修饰符,它有以下两种作用:
- 声明一个可以在之后初始化的非空变量
- 懒初始化一个变量
Dart的控制流分析通常可以在使用不可为null的变量之前检测该变量何时设置为非null值,但有时分析会失败。两种常见的情况是顶级变量和实例变量:Dart通常无法确定它们是否已设置,因此不会尝试。
如果你确定某个变量在使用前已赋值,但Dart未检测到,则可以通过将该变量标记为late
来修复错误(如果未能初始化late
修饰的变量,则在该变量被使用时会发生运行时错误。):
late String description;
void main() {
description = 'Feijoada!';
print(description);
}
如果你使用late修饰一个变量,但在声明时就进行初始化,初始化器也只会在第一次使用该变量时运行。这种惰性初始化在以下几种情况下很方便:
- 变量有可能不会被用到,并且初始化它的成本很高。
- 一个实例变量在初始化时需要访问
this
。
在以下示例中,如果从未使用过temperature
变量,则程序运行过程中不会调用开销昂贵的readThermometer()函数:
// 未在其他地方使用到 temperature 变量
late String temperature = readThermometer(); // 懒初始化.
Final 和 Const
如果你不想更改一个变量,可以使用关键字final
或者const
修饰变量,这两个关键字可以替代var
关键字或者加在一个具体的类型前。一个final
变量只可以被赋值一次;一个const
变量是一个编译时常量 (const
变量同时也是final
的)。
下面的示例中我们创建并设置两个final
变量:
final name = 'Bob'; // 无类型声明
final String nickname = 'Bobby';
你不能修改一个final
变量的值:
name = 'Alice'; // 错误: 一个final变量只能被赋值一次
使用关键字const
修饰变量表示该变量为编译时常量。如果使用const
修饰类
中的变量,则必须加上static
关键字,即static const
(顺序不能颠倒)。在声明const
变量时可以直接为其赋值,也可以使用其它的const
变量为其赋值:
const bar = 1000000; // 压力单位 (dynes/cm2)
const double atm = 1.01325 * bar; // 标准大气压
const
关键字不仅仅可以用来定义常量,还可以用来创建常量值,该常量值可以赋予给任何变量。你也可以将构造函数声明为const
的,这种类型的构造函数创建的对象是不可改变的。
var foo = const [];
final bar = const [];
const baz = []; // 和`const []`等效
如果使用初始化表达式为常量赋值可以省略掉关键字const
,比如上面的常量baz
的赋值就省略掉了const
。详情请查阅不要冗余地使用 const。
没有使用 final 或 const 修饰的变量的值是可以被更改的,即使这些变量之前引用过 const 的值。
foo = [1, 2, 3]; // [1, 2, 3] 是 const []
常量的值不可以被修改:
// baz 在上文中声明时被const修饰
baz = [42]; // 错误: 常量不能被二次赋值
你可以在常量中使用 类型检查和强制类型转换 (is
和as
)、 集合中的if
以及展开操作符 (...
和...?
):
const Object i = 3; // 其中i是具有int值的常量对象...
const list = [i as int]; // 使用类型转换
const map = {if (i is int) i: 'int'}; // 使用is和collection if。
const set = {if (list is List<int>) ...list}; // ...展开操作符
备注:虽然final对象不能被修改,但它的值可以被修改,而const对象则不行。
final nums = [1, 2, 3];
// nums = [4, 5] // 报错:final变量不可被二次赋值
nums[2] = 5; // 可修改数组中的值
print(nums); // 输出:[1, 2, 5]
const conNums = [1, 2, 3];
// conNums[1] = 4; 报错:常量不可被修改
print(conNums);