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

How can I make null-safety assertions to avoid using null check (!) or conditional (?) operators in Flutter?

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

这是一个例子:

String? string;

void test() {
  if (string != null) {
    print(string.length);
  }
}

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

The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').

然而,接收者实际上不能为空,因为它被 if (string != null) 块包裹着。使用 string?.lengthstring!.length 访问字段工作正常,但当我需要使用变量的不同字段或方法时可能会造成混淆。

String? string;

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

所有这些语句都会引发相同的错误。我也试过放置 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),
    ],
  );
}

这仍然是编译器的问题。

这些是为了健全的零安全。这就是为什么每当你开始调用一个函数/访问它时,通过使用确保变量不为空!或使用 ?.

为 null 提供其他情况

假设以下情况:

    if (string != null) {
        string=null; // Or through other function xyx() {string=null;} string becomes null then your if condition is void
        print(string.length);
        print(string.isNotEmpty);
        print(string.trim());
        print(string.contains('x'));
      }

// Still sound null safety that's why above is not allowed
    if (string != null) {
        string=null; // Or through other function xyx() {string=null;} string becomes null then your if condition is void
        print(string!.length);
        print(string!.isNotEmpty);
        print(string!.trim());
        print(string!.contains('x'));
      }

所以为了健全的空安全需要在访问字符串之前检查它是否不为空

根据您的意见,您需要将此可空字符串分配给不可空字符串(~isdatablank~ 表示字符串为空)并继续

String? string;
  String s=string??"~isdatablank~";
  if (s != "~isdatablank~") {
        print(s.length);
        print(s.isNotEmpty);
        print(s.trim());
        print(s.contains('x'));
      }

However, the receiver actually can't be null since it's wrapped

这个假设是完全错误的。

你的变量是一个全局变量和你程序的任何其他部分,通过multi-threading或其他恶作剧可以滑动在 if 和下一行之间 更改 变量。

这就是为什么只有 局部变量 可以提升为它们的 non-null 等价物,当编译器证明它们在某些代码执行分支中不能为空时,例如 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);       
  }
}