Dart 中的 null 检查运算符是如何工作的

How does the null check operator work in Dart

我正在使用 this 存储库来熟悉 Amazon 的 Cognito 用户系统。在文件 lib/screens/signup_screen.dart 中,从第 27 行开始有这段代码:

          TextFormField(
            keyboardType: TextInputType.emailAddress,
            decoration: InputDecoration(labelText: "Email"),
            controller: _emailController,
            validator: (value) =>
                !validateEmail(value) ? "Email is Invalid" : null,
          ),

但是,由于自版本 2.x 以来我们在 Dart 中具有空安全性,因此这段代码失败并显示错误消息:The argument type 'String?' can't be assigned to the parameter type 'String'.

我从中得到的是 value 可能不等于 null 并且代码不能保证它是。如果我错了,请纠正我,我也希望有人能向我解释为什么代码不能保证这里的空安全。如果文本字段为空,value 应该等于 "" 而不是 null.

无论如何,我决定使用三元运算符来解决这个问题:

!validateEmail(value == null ? "" : value) ? ...

IDE 建议我更正为:

!validateEmail(value ?? "") ? ...

Dart 还建议插入空检查作为另一种选择:

!validateEmail(value!) ? ....

到目前为止,我一直在使用这些修复程序作为一种变通方法来快速生成代码,而没有试图了解实际发生的事情。

那么这些方法有什么区别呢?第二种方法中的??是否集成了== null检查,是否和写value == null ? "" : value一模一样?

此外,nullcheck value! 有什么作用?是的,它检查 value 是否等于 null,但是当 value 实际上等于 null 时它对我有什么作用?

?? 是一个 null-aware 运算符,它 returns 其左侧的表达式,除非该表达式的值为空,在这种情况下,它计算 returns右边的表达式:

print(1 ?? 3); // <-- Prints 1.
print(null ?? 12); // <-- Prints 12.

这与执行三元运算符相同,但更具可读性。

bang 运算符 ! 抛弃了变量的可空性,这意味着您明确地说该值不能是 null.

Of course, like any cast, using ! comes with a loss of static safety. The cast must be checked at runtime to preserve soundness and it may fail and throw an exception.

如需进一步阅读,请查看 documentation

您可以在此处开始了解有关 Dart 中声音空安全的更多信息:Understanding Null Safety

空断言 value! 等于转换为 non-nullable 类型:value as String。如果 value 为空,它会引发异常。

条件 ?? 运算符如您所愿:value ?? "" 是 shorthand 等价于 value != null ? value : ""

What I got from that is that value may not be equal to null and the code cannot guarantee that as it is.

value 可能null,但是validateEmail要求它的参数是而不是 null.

can explain to me why the code cannot guarantee null safety here. If the textfield is empty, value should be equal to "" instead of null.

因为 TextFormField's constructor specifies. Its validator parameter is declared to be a FormFieldValidator<String>?, and FormFieldValidator<T> 被定义为 String? Function(T? value)。换句话说,validator 回调被声明为一个必须接受 null 作为参数的函数。编译器没有语义知识,无法知道 TextFormField 是否会在实践中使用 null 而不是空字符串实际调用该回调。

So what's the difference between these methods? Does the ?? in the second method have an integrated == null check and is it exactly the same as writing value == null ? "" : value?

?? 是 Dart 的 null-aware 运算符之一;它会自动为您检查 nullAs stated in the Dart Language Tour:

expr1 ?? expr2

If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.

所以是的,它等同于 expr1 == null ? expr2 : expr1(除了 ?? 只会评估 expr1 一次,如果评估有副作用,这很重要)。无论如何,您应该更喜欢 ??,因为它能更好地传达意图。

Also, what does the nullcheck value! do? Yes, it checks if value is equal to null, but what does it do for me when value is in fact equal to null?

value! 抛出异常 (特别是 TypeError)如果 value 在运行时结果是 null .不要使用 !,除非你可以从逻辑上保证 value 不会是 null