ZetCode

Dart 作用域

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

在 Dart 中,**作用域** 定义了变量和函数的可见性及生命周期,决定了在程序中标识符可以在何处被访问。

Dart 遵循 **词法作用域** 模型,这意味着变量的可见性由代码的结构而非执行流程决定。变量从声明点开始,在其封闭块的末尾之前一直可访问,从而确保了嵌套函数和闭包中的行为可预测。

变量的作用域由其声明位置决定。Dart 支持多种类型的作用域:

当一个局部变量与全局变量或外层作用域中的变量同名时,就会发生**遮蔽**。在局部作用域内,局部变量具有优先权,有效地隐藏了外层变量。

全局作用域

在任何函数或类外部声明的变量具有全局作用域。它们可以从程序的任何地方访问。

main.dart
// 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

局部作用域

在函数或块内部声明的变量具有局部作用域。它们仅在该函数或块内可访问。

main.dart
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

函数参数作用域

函数参数的作用域仅限于函数体。它们的行为类似于局部变量,但会用传递的参数进行初始化。

main.dart
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!

遮蔽变量

当一个局部变量与外层作用域中的变量同名时,它会遮蔽外层变量。内层变量具有优先权。

main.dart
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 函数可以捕获其词法作用域中的变量,从而创建闭包。即使在作用域外执行,函数仍保留对这些变量的访问权限。

main.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 的作用域规则,展示了变量在不同上下文中的可见性如何工作。

作者

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

列出 所有 Dart 教程