flutter Null检查不会导致Dart中的类型提升

hsvhsicv  于 2023-05-19  发布在  Flutter
关注(0)|答案(3)|浏览(173)

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

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
  }
}

我得到一个编译时错误:
错误:类型为“String?无法从函数“myString”返回“”,因为它的返回类型为“String”。
或者如果我尝试得到_mySting.length,我会得到以下错误:
不能无条件访问属性“length”,因为接收器可以是“null”。
我以为做null检查会把_myString提升为不可为null的类型。为什么不呢?
My question是在GitHub上解决的,所以我在下面发布了一个答案。

jw5wzhpr

jw5wzhpr1#

Dart工程师Erik Ernst在GitHub上说:
类型提升仅适用于局部变量。提升示例变量是不合理的,因为它可能被运行计算的getter重写,并且每次调用它时返回不同的对象。有关类似于类型提升但基于动态检查的机制的讨论,请参阅dart-lang/language#1188,并提供一些相关讨论的链接。
所以本地类型提升是有效的:

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

但示例变量不促进。为此,您需要手动告诉Dart,您确定示例变量在本例中不是null,方法是使用!操作符:

class MyClass {
  String? _myString;
  
  String myMethod() {
    if (_myString == null) {
      return '';
    }
    
    return _myString!;
  }
}
zaqlnxep

zaqlnxep2#

错误:

假设,这是你的代码,你正在对示例变量进行null检查,仍然看到一个错误:

class Foo {
  int? x;

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

无法无条件调用方法“toDouble”,因为接收器可以为“null”。
您在这样的代码中看到的错误是因为Getter不会提升为不可空的对应项。让我们来谈谈为什么。

错误原因:

比如说,有一个类Bar,它扩展了Foo并覆盖了x字段,实现方式如下:

class Bar extends Foo {
  @override
  int? get x => (++_count).isOdd ? 1 : null;
  int _count = 0;
}

如果你这么做了

Bar().toDouble();

您可能会遇到一个运行时空错误,这就是为什么禁止getters类型提升的原因。

解决方案:

我们需要抛弃int?的空性。通常有三种方法可以做到这一点。

*使用局部变量(推荐)

double toDouble() {
  final x = this.x; // <-- Use a local variable
  if (x != null) return x.toDouble(); 
  return -1;
}

*使用?.??

double toDouble() {
  return x?.toDouble() ?? -1; // Provide a default value
}

*使用空Assert运算符(!)

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

double toDouble() {
  return x!.toDouble(); // Null assertion operator
}
xu3bshqb

xu3bshqb3#

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

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

尝试使用条件调用?或者一个无效的安全检查器!

相关问题