8

如果我编写以下代码,则在nullsafety.dartpad.dev中:

void main() {
  String? name = 'Bob';
  print(name.length);
}

我收到以下编译时错误:

值可以为“空”的表达式必须先进行空检查,然后才能取消引用

以及以下运行时错误:

无法在“字符串”上访问属性“长度”?因为它可能为空。

空检查文档上的类型提升说:

该语言也更聪明地了解什么样的表达方式会导致提升。明确的== null!= null当然有效。as但是使用,或 assignments!或我们将很快介绍的后缀运算符的显式强制转换也会导致提升。总体目标是,如果代码是动态正确的并且可以合理地静态计算出来,那么分析应该足够聪明才能做到这一点。

问题

name上面的代码中,不可能为 null。该文档还说分配应该导致类型提升。我误解了类型提升还是 DartPad 中的错误?

澄清

由于一些答案为错误消息提供了解决方案,因此我应该澄清一下,我并不是要解决上面的编码问题。相反,我是说我认为代码应该像它一样工作。但事实并非如此。为什么不?

4

2 回答 2

5

此答案是对添加到原始问题的赏金的回应。赏金写道:

请解释与 Dart 中的类型提升有何String?不同以及如何工作。String

细绳?与字符串

该类型String?可以包含字符串或null. 这里有些例子:

String? string1 = 'Hello world';
String? string2 = 'I ❤️ Dart';
String? string3 = '';
String? string4 = null;

另一方面,String 类型只能包含字符串(也就是说,一旦 null 安全是 Dart 的一部分)。它不能包含null. 这里有些例子:

String string1 = 'Hello world';
String string2 = 'I ❤️ Dart';
String string3 = '';

如果您尝试执行以下操作:

String string4 = null;

你会得到编译时错误:

A value of type 'Null' can't be assigned to a variable of type 'String'.

类型String不能null超过intlike3boollike 。true这就是零安全的全部意义所在。如果您有一个类型为 的变量,则String可以保证该变量永远不会是null

类型提升的工作原理

如果编译器可以在逻辑上确定可空类型(如String?)永远不会是null,则它将类型转换(或提升)为其不可为空的对应类型(如String)。

这是一个正确的示例:

void printNameLength(String? name) {
  if (name == null) {
    return;
  }
  print(name.length);
}

虽然参数name可以为空,但如果它确实是,null那么函数会提前返回。当你到达的时候name.length,编译器肯定知道这是name不可能的null。所以编译器将 name 提升为String?to String。该表达式name.length永远不会导致崩溃。

这里有一个类似的例子:

String? name;
name = 'Bob';
print(name.length);

虽然name在这里也可以为空,但字符串文字'Bob'显然是非空的。这也导致name被提升为不可为空的String

最初的问题是关于以下内容:

String? name = 'Bob';
print(name.length);

似乎这也应该将 name 提升为 non-nullable String,但事实并非如此。正如@lrn(谷歌工程师)在评论中指出的那样,这是一个错误,当出现空安全性时,这也将像前面的示例一样工作。也就是说,name将被提升为不可为空的String.

进一步阅读

于 2020-10-13T05:37:33.093 回答
0

我明白你在说什么。试试这个。

在此处输入图像描述

为了使类型提升起作用,您必须首先确认该值不为文档所述的空值。

正如你在图片中看到的那样,dart 能够进行类型提升或理解 name 不会为空,因为它会事先在 if 语句中检查它。

但是如果在 if 语句之外使用它而不事先检查它是否不为 null,dart 知道它可以随时再次分配为 null。这就是为什么它鼓励总是检查它是否为空。因为将来可以将任何实例化变量(已分配值的变量)分配为

于 2020-08-22T01:13:33.090 回答