【问题标题】:Why can a nullable value still be considered nullable inside the scope of an if statement that checks for nullability?为什么在检查可空性的 if 语句的范围内仍然可以将可空值视为可空值?
【发布时间】:2021-05-24 15:54:29
【问题描述】:

考虑这个演示:

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 一起使用。

【问题讨论】:

标签: dart dart-null-safety


【解决方案1】:

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

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

以下循环显示了一个示例,其中无法保证自动 nnull,即使在 --n 之前未将 n 分配为 null

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

为了确定n 是否可以在--n 处成为null,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;
    }
  }
}

【讨论】:

  • bang 运算符--!n; 无法为我编译。错误:Missing selector such as '.identifier' or '[0]'. Try adding a selector.。但是,我可以做到n = n! - 1。我错过了什么?
  • @offworldwelcome 我以为我在写这个答案时在 dartpad 中测试了该语法,但你没有遗漏任何东西。这是无效的。但是,建议使用此语法:github.com/dart-lang/language/blob/…。我将编辑我的答案以使其更准确。
  • 谢谢,您的评论很清楚。我在代码的前面(在空检查之前)有一个 for 循环来设置变量,这就是为什么我需要在空检查之后添加一个 bang 运算符。我认为这是一个应该在即将发布的 Dart 版本中修复的错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
  • 1970-01-01
相关资源
最近更新 更多