Dart 作用域
最后修改日期:2025 年 6 月 4 日
在 Dart 中,**作用域** 定义了变量和函数的可见性及生命周期,决定了在程序中标识符可以在何处被访问。
Dart 遵循 **词法作用域** 模型,这意味着变量的可见性由代码的结构而非执行流程决定。变量从声明点开始,在其封闭块的末尾之前一直可访问,从而确保了嵌套函数和闭包中的行为可预测。
变量的作用域由其声明位置决定。Dart 支持多种类型的作用域:
- 全局作用域: 在任何函数或类外部声明的变量。
- 局部作用域: 在函数或块内部声明的变量。
- 函数参数作用域: 函数的参数仅限于该函数内部。
- 块作用域: 在块(例如,在 if 语句内部)内声明的变量。
- 词法闭包: 函数可以捕获其周围作用域中的变量。
当一个局部变量与全局变量或外层作用域中的变量同名时,就会发生**遮蔽**。在局部作用域内,局部变量具有优先权,有效地隐藏了外层变量。
全局作用域
在任何函数或类外部声明的变量具有全局作用域。它们可以从程序的任何地方访问。
// Global variable
var globalVar = 'I am global';
void main() {
print(globalVar); // Accessible here
someFunction();
}
void someFunction() {
print(globalVar); // Also accessible here
}
globalVar 在任何函数外部声明,使其具有全局可访问性。main 和 someFunction 都可以访问和使用此变量。
$ dart main.dart I am global I am global
局部作用域
在函数或块内部声明的变量具有局部作用域。它们仅在该函数或块内可访问。
void main() {
var localVar = 'I am local';
print(localVar); // Works fine
if (true) {
var blockVar = 'I am block scoped';
print(blockVar); // Works here
}
// print(blockVar); // Error: Undefined name 'blockVar'
}
void anotherFunction() {
// print(localVar); // Error: Undefined name 'localVar'
}
localVar 仅在 main() 内可访问,而 blockVar 仅在 if 块内可访问。尝试在作用域外访问它们会导致错误。
$ dart main.dart I am local I am block scoped
函数参数作用域
函数参数的作用域仅限于函数体。它们的行为类似于局部变量,但会用传递的参数进行初始化。
void greet(String name) {
print('Hello, $name!');
// name is accessible here
}
void main() {
greet('Alice');
// print(name); // Error: Undefined name 'name'
}
name 参数仅在 greet 函数内可访问。尝试在函数外部使用它会像局部变量一样导致错误。
$ dart main.dart Hello, Alice!
遮蔽变量
当一个局部变量与外层作用域中的变量同名时,它会遮蔽外层变量。内层变量具有优先权。
var shadowed = 'Global';
void main() {
var shadowed = 'Local';
print(shadowed); // Prints local
if (true) {
var shadowed = 'Block';
print(shadowed); // Prints block
}
print(shadowed); // Prints local again
}
每次声明 shadowed 时,都会创建一个新的变量,该变量会隐藏该作用域中之前的变量。原始的全局变量保持不变但不可访问。
$ dart main.dart Local Block Local
词法闭包
Dart 函数可以捕获其词法作用域中的变量,从而创建闭包。即使在作用域外执行,函数仍保留对这些变量的访问权限。
Function makeCounter() {
var count = 0;
return () {
count++;
return count;
};
}
void main() {
var counter = makeCounter();
print(counter()); // 1
print(counter()); // 2
print(counter()); // 3
}
makeCounter 返回的匿名函数捕获了 count 变量。每次调用 counter 都会访问并修改同一个 count 变量,尽管它在 makeCounter 中是局部的。
$ dart main.dart 1 2 3
最佳实践
- 最小化全局变量: 尽可能使用局部变量。
- 清晰命名: 避免使用描述性名称进行遮蔽。
- 短作用域: 在所需最小的作用域中声明变量。
- 闭包意识: 注意闭包捕获了哪些变量。
来源
本教程通过实际示例涵盖了 Dart 的作用域规则,展示了变量在不同上下文中的可见性如何工作。
作者
列出 所有 Dart 教程。