04.Dart 基础 - 变量(var、默认值、late、final和const)

·  阅读 463

变量

var可以自行推断出类型

main(List<String> args) {
  var name = 'Bob';
  
  var a = 1, b = 2, c = 3;
  var d, e, f;
  print("a=${a} b=${b} d=${d} e=${e} f=${f}"); //a=1 b=2 d=null e=null f=null

  d = true;e = "123" ;f = 123;
  print("a=$a b=$b d=$d e=$e f=$f"); //a=1 b=2 d=true e=123 f=123
}
复制代码

变量仅存储对象的引用。这里名为 name 的变量存储了一个 String 类型对象的引用,“Bob” 则是该对象的值。

name 变量的类型被推断为 String,但是你可以为其指定类型。如果一个对象的引用不局限于单一的类型,可以将其指定为 Object(或 dynamic)类型。

dynamic name = 'Bob';
复制代码

另一种方式是显式声明可以推断出的类型:

String name = 'Bob';
复制代码

默认值

在 Dart 中,未初始化以及可空类型的变量拥有一个默认的初始值 null。(如果你未迁移至 空安全,所有变量都为可空类型。)即便数字也是如此,因为在 Dart 中一切皆为对象,数字也不例外。

int? lineCount;
assert(lineCount == null);
复制代码

assert() 的调用将会在生产环境的代码中被忽略掉。在开发过程中,assert(condition) 将会在 条件判断 为 false 时抛出一个异常。详情请查阅 Assert

  1. 如果启用空安全,则必须在使用非空变量之前初始化它们的值:
int lineCount = 0;
复制代码

不必在声明局部变量的地方初始化,但需要在使用它之前给它赋值。如下示例,因为Dart可以检测到lineCount在传递给print()时是非空的

void main(){
    int lineCount;
    lineCount = 0;
    print(lineCount);
}
复制代码

late 关键字实现延迟初始化

Dart 2.12添加了延迟加载修饰符,它有两个用例:

  • 声明一个不可空的变量,并在声明后初始化。
  • 延迟初始化变量。

通常Dart的控制流分析可以在使用非空变量之前检测到该变量是否被设置为非空值,但有时分析会失败。两种常见的情况是顶级变量和实例变量:Dart通常不能确定是否设置了它们,所以它不会尝试。
如果你确定一个变量在使用之前就被设置了,但是Dart不同意,你可以通过标记变量为late来解决这个错误:

late String description;

void main() {
  description = 'Feijoada!';
  print(description);
}
复制代码

如果late延迟初始化变量失败,则在使用该变量时发生运行时错误。\

如果将一个变量标记为late,但在声明时初始化它,那么初始化式将在该变量第一次使用时运行。这种延迟初始化在以下几种情况下很方便:

  • 该变量可能不需要,并且初始化它的代价很高。
  • 你正在初始化一个实例变量,它的初始化需要访问这个。

在下面的例子中,如果从未使用过temperature变量,则不会调用_readThermometer()函数:

// This is the program's only call to _readThermometer().
late String temperature = _readThermometer(); // Lazily initialized.
复制代码

Final 和 Const

如果你不想更改一个变量,可以使用关键字 final 或者 const 修饰变量,这两个关键字可以替代 var 关键字或者加在一个具体的类型前。一个 final 变量只可以被赋值一次;一个 const 变量是一个编译时常量(const 变量同时也是 final 的)。顶层的 final 变量或者类的 final 变量在其第一次使用的时候被初始化。

虽然final对象不能被修改,但是它的字段可以被修改。相比之下,const对象及其字段是不可更改的:它们是不可变的。

实例变量 可以是 final 的但不可以是 const

下面的示例中我们创建并设置两个 final 变量:

final name = 'Bob'; // 没有类型注释
final String nickname = 'Bobby';
复制代码

你不能修改 final 变量的值:

name = 'Alice'; // Error: final变量只能设置一次.
复制代码

使用关键字 const 修饰变量表示该变量为 编译时常量。如果使用 const 修饰类中的变量,则必须加上 static 关键字,即 static const(译者注:顺序不能颠倒)。在声明 const 变量时可以直接为其赋值,也可以使用其它的 const 变量为其赋值:

const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere
复制代码

const 关键字不仅仅可以用来定义常量,还可以用来创建 常量值,该常量值可以赋予给任何变量。你也可以将构造函数声明为 const 的,这种类型的构造函数创建的对象是不可改变的。

var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`
复制代码

如果使用初始化表达式为常量赋值可以省略掉关键字 const,比如上面的常量 baz 的赋值就省略掉了 const。详情请查阅 不要冗余地使用 const

没有使用 final 或 const 修饰的变量的值是可以被更改的,即使这些变量之前引用过 const 的值。

foo = [1, 2, 3]; // Was const []
复制代码

常量的值不可以被修改:

baz = [42]; // Error: 常量变量不能被赋值.
复制代码

你可以在常量中使用 类型检查和强制类型转换 (is 和 as)、 集合中的 if 以及 展开操作符 (... 和 ...?):

const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {if (i is int) i: 'int'}; // Use is and collection if.
const set = {if (list is List<int>) ...list}; // ...and a spread.
复制代码
分类:
前端
标签: