Dart 变量
最后修改日期:2025 年 6 月 4 日
在 Dart 中,变量用于存储和操作程序中的数据。它们充当程序执行期间可以更改的值的命名容器。
Dart 是静态类型的,但支持类型推断,允许显式和隐式变量声明。变量必须在使用前声明,并且可以在声明时或稍后初始化。
变量声明和初始化
Dart 中的变量可以使用 var 关键字或显式类型声明。var 关键字允许 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 变量是编译时常量。
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 类型系统的根。
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 值。不可空变量必须始终包含一个值。
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 中的变量具有词法作用域,这意味着它们仅在其声明的块内可访问。全局变量在整个程序中都可访问。
// 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 函数时。通过使用 _
,开发人员可以只关注他们关心的值,同时安全地忽略其余部分。这不仅避免了编译器关于未使用的变量的警告,而且还向审查代码的其他开发人员传达了意图。
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 }
在上面的示例中,下划线用于在元组解构时忽略第二个值,在列表模式中匹配但忽略元素,以及作为未使用的函数参数。其他示例显示了如何在循环和嵌套模式中使用通配符来进一步简化代码。
最佳实践
- 类型推断:对于类型明显的局部变量,请优先使用 var。
- 不可变性:对于不应更改的变量,请使用 final。
- 空安全:除非 null 是有效状态,否则避免使用可空类型。
- 作用域:尽量保持变量作用域尽可能小。
- 命名:使用遵循 lowerCamelCase 的描述性名称。
来源
本教程涵盖了 Dart 变量,并提供了实用示例,演示了 Dart 中的声明、初始化和各种变量类型。
作者
列出 所有 Dart 教程。