如何做出 null 安全断言以避免在 Flutter 中使用 null 检查 (!) 或条件 (?) 运算符?

ras*_*yaz 5 dart flutter dart-null-safety

当我在语句中使用变量时,Dart 编译器不明白该变量不能为 nullif (x != null)。它仍然需要使用条件?或空检查!运算符来访问变量的字段或方法之一。

这是一个例子:

String? string;

void test() {
  if (string != null) {
    print(string.length);
  }
}
Run Code Online (Sandbox Code Playgroud)

这会产生一个编译时错误并表示

无法无条件访问属性“length”,因为接收者可以为“null”。尝试使访问成为有条件的(使用“?.”)或向目标添加空检查(“!”)。

然而,接收者实际上不能为空,因为它是用if (string != null)块包裹的。string?.length使用或访问字段string!.length效果很好,但当我需要使用变量的不同字段或方法时,可能会感到困惑。

String? string;

void test() {
  if (string != null) {
    print(string.length);
    print(string.isNotEmpty);
    print(string.trim());
    print(string.contains('x'));
  }
}
Run Code Online (Sandbox Code Playgroud)

所有这些陈述都会引发相同的错误。我也尝试放置assert(string != null);,但编译器仍然不明白该字符串不为空。

举一个更复杂的例子;

User? user;

@override
Widget build(BuildContext context) {
  if (user == null) {
    return Text('No user available');
  } else {
    return buildUserDetails();
  }
}

Widget buildUserDetails() {
  return Column(
    children: [
      Text(user.name),
      Text(user.email),
    ],
  );
}
Run Code Online (Sandbox Code Playgroud)

这对于编译器来说仍然是一个问题。

nvo*_*igt 8

然而,接收者实际上不能为空,因为它被包装了

这个假设是完全错误的。

您的变量是全局变量,程序的任何其他部分通过多线程或其他恶作剧都可以if在您的行和下一行之间插入并更改变量。

这就是为什么当编译器证明局部变量在某些代码执行分支(if.

以下内容将完全正常工作,因为您正在操作一个局部变量,编译器可以确定该变量不会被外部操作更改:

String? string;

void test() {
  final local = string;
  if (local != null) {

    // here, local was promoted from "string?" to "string"
    // since the "if" makes sure it is not null AND
    // the variable is not accessible to anything but this
    // function, so it cannot be changed from the outside
    // and is contrained to the sequential flow of this method.

    print(local.length);       
  }
}
Run Code Online (Sandbox Code Playgroud)