为什么可空值在检查可空性的 if 语句范围内仍然被认为是可空的?

Why can a nullable value still be considered nullable inside the scope of an if statement that checks for nullability?

考虑这个演示:

void test(int? n) {
  if (n != null) { // let's make sure n is not null
    ++n; // ok; n is assumed to be non-null

    if (n < 0) {
      n = n.abs(); // ok; n is not null in inner scope
    }

    while (n != 0) {
      --n; // error: the method '-' can't be unconditionally invoked because the receiver can be 'null'
    }
  }
}

为什么 n 仍然被认为是 int?while(...) { ... } 块内?我正在使用 VSCode 和最新版本的 Dart。

与方法主体中前面的代码不同,while 循环中的代码可以 运行 多次。您可以在循环的一次迭代中将 null 分配给 n,因此可以在 null 对象上调用 --

Dart 的静态分析可以看出 n 不会在非循环代码中相对容易地为 null ,它只需要遍历每一行看是否有可能 null任务。对于循环,Dart 的分析就没那么聪明了。我猜无法完成此检测,因为它实际上需要 运行 循环代码以确定 n 是否可以再次变为 null

以下循环显示了一个示例,其中自动 n 不能保证为 null,即使 n 未在 [ 之前分配为 null =26=]:

while (n != 0) {
  --n; // error: the method '-' can't be unconditionally invoked because the receiver can be 'null'
  if(n == 5) {
    n = null;
  }
}

为了确定 n 是否可以 null--n,Dart 的分析将 向前看 以查看 n 分配给 null.


在这种情况下,Dart 的分析无法准确确定变量是否可以 null 这就是 bang 运算符存在的原因:

void test(int? n) {
  if (n != null) { // let's make sure n is not null
    ++n; // ok; n is assumed to be non-null

    if (n < 0) {
      n = n.abs(); // ok; n is not null in inner scope
    }

    while (n != 0) {
      n = n! - 1;
    }
  }
}

或者,您可以为您的特定示例使用本地不可空变量:

void test(int? n) {
  if (n != null) { // let's make sure n is not null
    int nLocal = n;
    ++nLocal; // ok; n is assumed to be non-null

    if (n < 0) {
      nLocal = nLocal.abs(); // ok; n is not null in inner scope
    }

    while (n != 0) {
      --nLocal;
    }
  }
}