分配非空值文字时的空安全类型提升

Sur*_*gch 7 dart type-promotion dart-null-safety

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

void main() {
  String? name = 'Bob';
  print(name.length);
}
Run Code Online (Sandbox Code Playgroud)

我收到以下编译时错误:

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

以及以下运行时错误:

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

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

该语言在什么样的表达方式会导致提升方面也更加聪明。一个明确的== null!= null当然的作品。但是使用as赋值或后缀!运算符的显式转换也会导致提升。总体目标是,如果代码是动态正确的,并且可以合理地静态计算出来,那么分析应该足够聪明来做到这一点。

有没有可行的方法name可能是空在上面的代码。该文档还说分配应该导致类型提升。我误解了类型提升还是 DartPad 中的错误?

澄清

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

Sur*_*gch 5

此答案是对添加到原始问题中的赏金的回应。赏金内容如下:

\n
\n

请解释String?与 Dart 中的 type\npromotion 有何不同String以及其工作原理。

\n
\n

细绳?与字符串

\n

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

\n
String? string1 = \'Hello world\';\nString? string2 = \'I \xe2\x9d\xa4\xef\xb8\x8f Dart\';\nString? string3 = \'\';\nString? string4 = null;\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
String string1 = \'Hello world\';\nString string2 = \'I \xe2\x9d\xa4\xef\xb8\x8f Dart\';\nString string3 = \'\';\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
String string4 = null;\n
Run Code Online (Sandbox Code Playgroud)\n

你会得到编译时错误:

\n
A value of type \'Null\' can\'t be assigned to a variable of type \'String\'.\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

类型提升如何运作

\n

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

\n

下面是一个例子,说明这一点是正确的:

\n
void printNameLength(String? name) {\n  if (name == null) {\n    return;\n  }\n  print(name.length);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

尽管该参数name可以为空,但如果它实际上可以为空,null则该函数会提前返回。当您到达时name.length,编译器肯定知道这是name不可能的null。因此编译器将 name 从 提升String?String。该表达式name.length永远不会导致崩溃。

\n

类似的例子在这里:

\n
String? string1 = \'Hello world\';\nString? string2 = \'I \xe2\x9d\xa4\xef\xb8\x8f Dart\';\nString? string3 = \'\';\nString? string4 = null;\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n
String string1 = \'Hello world\';\nString string2 = \'I \xe2\x9d\xa4\xef\xb8\x8f Dart\';\nString string3 = \'\';\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

进一步阅读

\n\n