变量
这是一个创建和初始化变量的示例
var name = 'Bob';变量存储引用。名为 name 的变量包含对值为“Bob”的 String 对象的引用。
name 变量的类型被推断为 String,但您可以通过明确指定来更改该类型。如果一个对象不限于单一类型,请指定 Object 类型(如果需要,也可指定 dynamic)。
Object name = 'Bob';另一种选择是显式声明将被推断的类型
String name = 'Bob';空安全
#Dart 语言强制执行健全的空安全。
空安全可防止因意外访问设置为 null 的变量而导致的错误。此错误称为空解引用错误。当您在评估为 null 的表达式上访问属性或调用方法时,会发生空解引用错误。此规则的例外情况是 null 支持该属性或方法,例如 toString() 或 hashCode。通过空安全,Dart 编译器在编译时检测这些潜在错误。
例如,假设您想查找一个 int 变量 i 的绝对值。如果 i 为 null,则调用 i.abs() 会导致空解引用错误。在其他语言中,尝试这样做可能会导致运行时错误,但 Dart 的编译器禁止这些操作。因此,Dart 应用程序不会导致运行时错误。
空安全引入了三个关键变更
当您为变量、参数或其他相关组件指定类型时,可以控制该类型是否允许
null。要启用可空性,您需要在类型声明的末尾添加一个?。dartString? name // Nullable type. Can be `null` or string. String name // Non-nullable type. Cannot be `null` but can be string.您必须在使用变量之前对其进行初始化。可空变量默认为
null,因此它们默认会被初始化。Dart 不为不可空类型设置初始值。它强制您设置初始值。Dart 不允许您观察未初始化的变量。这可以防止您访问接收者类型可能为null但null不支持所使用的方法或属性的属性或调用方法。您不能访问可空类型表达式上的属性或调用方法。同样的例外也适用于
null支持的属性或方法,例如hashCode或toString()。
健全的空安全将潜在的运行时错误转化为编辑时分析错误。当不可空变量出现以下情况时,空安全会对其进行标记:
- 未用非空值初始化。
- 被赋予了
null值。
此检查允许您在部署应用程序之前修复这些错误。
默认值
#具有可空类型的未初始化变量的初始值为 null。即使是数字类型的变量最初也是空值,因为数字(像 Dart 中的所有其他事物一样)都是对象。
int? lineCount;
assert(lineCount == null);使用空安全时,您必须在使用不可空变量之前初始化其值
int lineCount = 0;您不必在声明局部变量时就对其进行初始化,但您需要在其使用之前为其赋值。例如,以下代码是有效的,因为 Dart 可以检测到 lineCount 在传递给 print() 时是非空的
int lineCount;
if (weLikeToCount) {
lineCount = countLines();
} else {
lineCount = 0;
}
print(lineCount);顶层变量和类变量是延迟初始化的;初始化代码在变量首次使用时运行。
Late 变量
#late 修饰符有两种用例
- 声明一个在声明后初始化的不可空变量。
- 延迟初始化变量。
通常,Dart 的控制流分析可以检测到不可空变量在使用前何时被设置为非空值,但有时分析会失败。两种常见情况是顶层变量和实例变量:Dart 通常无法确定它们是否已设置,因此它不会尝试。
如果您确定变量在使用前已设置,但 Dart 不同意,则可以通过将变量标记为 late 来修复该错误
late String description;
void main() {
description = 'Feijoada!';
print(description);
}当您将变量标记为 late 但在声明时对其进行初始化时,初始化器会在变量首次使用时运行。这种延迟初始化在以下几种情况下非常方便
- 变量可能不需要,并且初始化它成本很高。
- 您正在初始化一个实例变量,并且其初始化器需要访问
this。
在以下示例中,如果 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 name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';您不能更改 final 变量的值
name = 'Alice'; // Error: a final variable can only be set once.对您希望成为编译时常量的变量使用 const。如果 const 变量在类级别,请将其标记为 static const。在声明变量的地方,将其值设置为编译时常量,例如数字或字符串字面量、const 变量,或常量数字上的算术运算结果
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphereconst 关键字不仅用于声明常量变量。您还可以用它来创建常量值,以及声明创建常量值的构造函数。任何变量都可以拥有常量值。
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`您可以从 const 声明的初始化表达式中省略 const,如上面 baz 所示。有关详细信息,请参阅 不要冗余使用 const。
您可以更改非 final、非 const 变量的引用,即使它曾经具有 const 值
foo = [1, 2, 3]; // Was const []您不能更改 const 变量的值
baz = [42]; // Error: Constant variables can't be assigned a value.您可以定义使用类型检查和转换(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.有关使用 const 创建常量值的更多信息,请参阅列表、映射和类。
通配符变量
#名称为 _ 的通配符变量声明了一个非绑定的局部变量或参数;本质上,它是一个占位符。如果存在初始化器,它仍会执行,但值不可访问。在同一命名空间中可以存在多个名为 _ 的声明,而不会发生命名冲突错误。
顶层声明或可能影响库隐私的成员不适用于通配符变量。块范围内的局部声明,例如以下示例,可以声明通配符
局部变量声明。
dartmain() { var _ = 1; int _ = 2; }for 循环变量声明。
dartfor (var _ in list) {}catch 子句参数。
darttry { throw '!'; } catch (_) { print('oops'); }泛型和函数类型参数。
dartclass T<_> {} void genericFunction<_>() {} takeGenericCallback(<_>() => true);函数参数。
dartFoo(_, this._, super._, void _()) {} list.where((_) => true); void f(void g(int _, bool _)) {} typedef T = void Function(String _, String _);