26

我正在升级一个基于 Flutter 框架的个人包。我在 Flutter Text 小部件源代码中注意到这里有一个空检查:

if (textSpan != null) {
  properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}

但是,textSpan!仍在使用!运算符。不应该textSpan在不使用!运算符的情况下提升为不可为空的类型吗?但是,尝试删除运算符会出现以下错误:

An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.

这是一个独立的示例:

class MyClass {
  String? _myString;
  
  String get myString {
    if (_myString == null) {
      return '';
    }
    
    return _myString; //   <-- error here
  }
}

我得到一个编译时错误:

错误:“字符串?”类型的值 无法从函数“myString”返回,因为它的返回类型为“String”。

或者,如果我尝试_mySting.length获取以下错误:

不能无条件访问属性“长度”,因为接收者可以为“空”。

我认为进行 null 检查会提升_myString为不可为 null 的类型。为什么不呢?

我的问题在 GitHub 上得到了解决,所以我在下面发布了一个答案。

4

3 回答 3

34

Dart 工程师 Erik Ernst在 GitHub 上说

类型提升仅适用于局部变量。... 实例变量的提升并不合理,因为它可能被运行计算并在每次调用时返回不同对象的 getter 覆盖。参照。dart-lang/language#1188用于讨论类似于类型提升但基于动态检查的机制,并提供一些相关讨论的链接。

所以本地类型推广有效:

  String myMethod(String? myString) {
    if (myString == null) {
      return '';
    }
    
    return myString;
  }

但是实例变量不会提升。为此,您需要使用运算符手动告诉 Dart 在这种情况下您确定实例变量不为空!

class MyClass {
  String? _myString;
  
  String myMethod() {
    if (_myString == null) {
      return '';
    }
    
    return _myString!;
  }
}
于 2020-11-27T10:17:16.953 回答
18

错误:

假设这是您的代码,您正在对实例变量进行空检查,但仍然看到错误:

class Foo {
  int? i = 0;

  double func() {
    if (i != null) return i.toDouble(); // <-- Error
    return -1;
  }
}

不能无条件地调用方法“toDouble”,因为接收者可以为“null”。

您在这样的代码中看到的错误是因为Getter 没有提升为它们的不可为空的对应物。让我们谈谈其中的原因。


错误原因:

比方说,有一个类Bar扩展Foo和覆盖i变量并且不为其分配任何值(保留它null):

class Bar extends Foo {
  @override
  int? i;
}

所以,如果你能做到

print(Bar().func() * 2);

您会遇到运行时 null 错误,这就是禁止 getter 类型提升的原因。


解决方案:

我们需要从int?. 通常有 3 种方法可以做到这一点(更多方法包括使用as,is等)

  • 使用局部变量(推荐)

    double bar() {
      var i = this.i; // <-- Use of local variable.
      if (i != null) return i.toDouble();
      return -1;
    }
    
  • 采用 ?。和 ??

    double bar() {
      return i?.toDouble() ?? -1; // Provide some default value.
    }
    
  • 使用 Bang 运算符 (!)

    只有当您 100% 确定变量 ( i) 永远不会是时,才应该使用此解决方案null

    double bar() {
      return i!.toDouble(); // <-- Bang operator in play.
    }
    
于 2021-04-04T13:57:06.533 回答
0

风格: Theme.of(context).textTheme.headline5!.copyWith(

style: Theme.of(context).textTheme.headline5!.copyWith(
                        color: Colors.white

尝试使用 ? 或空安全检查器 - !

于 2021-09-15T18:17:08.063 回答