为什么 Dart 程序的行为会根据使用词法作用域时声明变量的位置而有所不同?

Pau*_*aul 2 lexical-scope dart

今天我遇到了 Dart 看起来非常奇怪的行为。我对局部变量和词法作用域的理解一定有问题。让我们来看一些代码。上下文是从数字到字母的测试等级转换,但这对于理解并不重要。

首先,考虑这段代码,它按预期工作:

void main() {
  final pairs = <List>[
    [95, 'A'],
    [85, 'B'],
  ];

  for (final pair in pairs) {
    int number = pair[0];
    String letter = pair[1];
    test('$number converts to $letter', () {
      final actual = convert(number);
      expect(actual, letter);
    });
  }
}

String convert(int value) => value >= 90 ? 'A' : 'B';
Run Code Online (Sandbox Code Playgroud)

运行测试并通过。将第二行测试数据从85改为95,第二次测试失败。我明白这一点。

现在考虑这个替代实现。请注意,唯一的区别是numberletter变量现在是在for循环外部声明的。

void main() {
  final pairs = <List>[
    [95, 'A'],
    [85, 'B'],
  ];

  int number;
  String letter;

  for (final pair in pairs) {
    number = pair[0];
    letter = pair[1];
    test('$number converts to $letter', () {
      final actual = convert(number);
      expect(actual, letter);
    });
  }
}

String convert(int value) => value >= 90 ? 'A' : 'B';
Run Code Online (Sandbox Code Playgroud)

按原样运行此代码会产生预期结果:两个测试成功,它们的名称是“95 转换为 A”和“85 转换为 B”。但是,现在将测试数据中的 85 更改为 95。现在,两个测试都失败了。测试的名称正如人们所期望的那样:“95 转换为 A”和“95 转换为 B”。

我尝试在测试方法中设置断点来解决这个问题。运行测试时,第一个测试的名称是“95 转换为 A”,但在该测试主体内, 的值letter是“B”。

我与编程语言打交道已经很长时间了,但我却傻眼了。有人可以向我解释一下这里发生了什么吗?我不明白为什么这两个程序会有不同的行为。

lrn*_*lrn 5

测试框架的工作方式是,它运行一次来​​查找所有测试,但实际上尚未执行测试主体。

然后,测试运行程序运行在第一遍中收集的测试。

您的代码创建一组变量,并在第一遍中为它们分配两次,并注册两个测试。然后运行测试,两者都会看到最新的变量分配。

test这就是为什么您需要通过在循环内创建变量来确保变量对于 的调用是唯一的,或者确保变量通过setUp调用进行初始化,因为每个测试都会调用这些变量。