ZetCode

Dart 变量

最后修改日期:2025 年 6 月 4 日

在 Dart 中,变量用于存储和操作程序中的数据。它们充当程序执行期间可以更改的值的命名容器。

Dart 是静态类型的,但支持类型推断,允许显式和隐式变量声明。变量必须在使用前声明,并且可以在声明时或稍后初始化。

变量声明和初始化

Dart 中的变量可以使用 var 关键字或显式类型声明。var 关键字允许 Dart 根据分配的值自动推断类型。

main.dart
void main() {
  // Using var with type inference
  var name = 'Alice';
  var age = 30;
  
  // Explicit type declaration
  String country = 'Canada';
  double height = 1.75;
  
  print('$name is $age years old from $country');
  print('Height: $height meters');
}

此示例展示了推断和显式变量声明。当我们希望 Dart 推断类型时使用 var 关键字,而显式类型使代码更具可读性并强制执行类型安全。

$ dart main.dart
Alice is 30 years old from Canada
Height: 1.75 meters

Final 和 Const 变量

Dart 提供了 final 和 const 关键字,用于声明初始化后不应更改的变量。final 变量只能设置一次,而 const 变量是编译时常量。

main.dart
void main() {
  // final variable (runtime constant)
  final currentYear = DateTime.now().year;
  
  // const variable (compile-time constant)
  const pi = 3.14159;
  const maxAttempts = 3;
  
  print('Current year: $currentYear');
  print('PI value: $pi');
  print('Maximum attempts: $maxAttempts');
  
  // This would cause an error:
  // pi = 3.14;
}

final 变量在访问时初始化,而 const 变量必须在编译时使用常量值初始化。两者都防止重新赋值。

$ dart main.dart
Current year: 2025
PI value: 3.14159
Maximum attempts: 3

Dynamic 和 Object 类型

Dart 为可以保存任何类型的变量提供了 dynamic 和 Object 类型。dynamic 禁用静态类型检查,而 Object 是 Dart 类型系统的根。

main.dart
void main() {
  dynamic dynamicValue = 'Hello';
  print('dynamicValue: $dynamicValue (${dynamicValue.runtimeType})');
  
  dynamicValue = 42;
  print('dynamicValue: $dynamicValue (${dynamicValue.runtimeType})');
  
  Object objectValue = 'World';
  print('objectValue: $objectValue (${objectValue.runtimeType})');
  
  // This would cause a runtime error:
  // print(objectValue.length);
  
  if (objectValue is String) {
    print('Length: ${objectValue.length}');
  }
}

dynamic 允许在没有类型检查的情况下更改类型和访问成员。Object 在访问成员之前需要类型检查。请谨慎使用 dynamic,因为它会降低类型安全性。

$ dart main.dart
dynamicValue: Hello (String)
dynamicValue: 42 (int)
objectValue: World (String)
Length: 5

可空变量

借助空安全,变量必须使用 ? 显式声明为可空,以保存 null 值。不可空变量必须始终包含一个值。

main.dart
void main() {
  // Non-nullable variable
  String name = 'Bob';
  // name = null; // Compile error
  
  // Nullable variable
  String? nickname = null;
  nickname = 'Bobby';
  
  print('Name: $name');
  print('Nickname: $nickname');
  
  // Null-aware operators
  int? age;
  int actualAge = age ?? 25;
  print('Age: $actualAge');
  
  // Null assertion operator (!)
  String? maybeString = 'Hello';
  print(maybeString!.length);
}

这演示了空安全特性。?? 运算符为 null 情况提供默认值,而 ! 断言值为非 null。空安全有助于防止 null 引用错误。

$ dart main.dart
Name: Bob
Nickname: Bobby
Age: 25
5

变量作用域

Dart 中的变量具有词法作用域,这意味着它们仅在其声明的块内可访问。全局变量在整个程序中都可访问。

main.dart
// Global variable
int globalCounter = 0;

void incrementCounter() {
  // Local variable
  int localCounter = 0;
  
  globalCounter++;
  localCounter++;
  
  print('Global: $globalCounter, Local: $localCounter');
}

void main() {
  incrementCounter();
  incrementCounter();
  
  // This would cause an error:
  // print(localCounter);
  
  print('Final global counter: $globalCounter');
}

globalCounter 在任何地方都可以访问,而 localCounter 仅在 incrementCounter() 中可访问。每次函数调用都会获得一个新的 localCounter 实例。

$ dart main.dart
Global: 1, Local: 1
Global: 2, Local: 1
Final global counter: 2

通配符变量

Dart 3.8 引入了通配符变量,允许开发人员使用下划线 (_) 作为占位符来忽略不需要的值。通配符变量可以在各种上下文中使用,例如模式匹配、解构赋值和函数参数,只要存在但不需要的值。此功能通过清楚地表明哪些值未被故意使用,使代码更简洁、更具表达力且更具自我文档化。通配符有助于消除不必要的变量名并减少混乱,使代码更易于阅读和维护。

通配符变量在模式匹配场景中尤其强大,例如 switch 语句、解构元组或集合,以及在定义不需要某些参数的回调或 lambda 函数时。通过使用 _,开发人员可以只关注他们关心的值,同时安全地忽略其余部分。这不仅避免了编译器关于未使用的变量的警告,而且还向审查代码的其他开发人员传达了意图。

main.dart
void main() {
  // Destructuring with wildcard
  var (a, _, c) = (1, 2, 3);
  print('a: $a, c: $c'); // Output: a: 1, c: 3

  // Pattern matching with wildcard
  var list = [10, 20, 30];
  switch (list) {
    case [_, int second, _]:
      print('Second element: $second');
  }

  // Function parameter wildcard
  void printFirst(int first, _) {
    print('First: $first');
  }
  printFirst(42, 'unused');

  // Using wildcards in for-each loops
  var pairs = [(1, 'one'), (2, 'two'), (3, 'three')];
  for (var (_, word) in pairs) {
    print(word); // Prints: one, two, three
  }

  // Ignoring multiple values in nested patterns
  var nested = (1, (2, 3));
  var (x, (_, z)) = nested;
  print('x: $x, z: $z'); // Output: x: 1, z: 3
}

在上面的示例中,下划线用于在元组解构时忽略第二个值,在列表模式中匹配但忽略元素,以及作为未使用的函数参数。其他示例显示了如何在循环和嵌套模式中使用通配符来进一步简化代码。

最佳实践

来源

Dart 变量文档

本教程涵盖了 Dart 变量,并提供了实用示例,演示了 Dart 中的声明、初始化和各种变量类型。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程