Dartnull安全性不适用于类字段
我已将我的 Dart 代码迁移到 NNBD / Null Safety。其中一些看起来像这样:
class Foo {
String? _a;
void foo() {
if (_a != null) {
_a += 'a';
}
}
}
class Bar {
Bar() {
_a = 'a';
}
String _a;
}
这会导致两个分析错误。对于_a += 'a';:
值可以为“空”的表达式必须先进行空检查,然后才能取消引用。尝试在取消引用之前检查该值是否为“空”。
对于Bar() {:
不可为空的实例字段 '_a' 必须被初始化。尝试添加初始化表达式,或在此构造函数中添加字段初始化器,或将其标记为“迟到”。
在这两种情况下,我已经完全按照错误提示做了!那是怎么回事?
我正在使用 Dart 2.12.0-133.2.beta(12 月 15 日星期二)。
编辑:我发现这个页面说:
分析器无法对整个应用程序的流程进行建模,因此它无法预测全局变量或类字段的值。
但这对我来说没有意义 -在这种情况下只有一个可能的流控制路径从if (_a != null)到_a += 'a';- 没有异步代码并且 Dart 是单线程的 - 所以它_a不是本地的并不重要。
并且错误消息Bar()显式说明了在构造函数中初始化字段的可能性。
回答
问题是即使类字段被标记为final. 下面的例子说明了这个问题:
class A {
final String? text = 'hello';
String? getText() {
if (text != null) {
return text;
} else {
return 'WAS NULL!';
}
}
}
class B extends A {
bool first = true;
@override
String? get text {
if (first) {
first = false;
return 'world';
} else {
return null;
}
}
}
void main() {
print(A().getText()); // hello
print(B().getText()); // null
}
本B类重写了text最后一个字段所以它返回一个值第一次有人问,但回报率null在此之后。您不能A以可以阻止这种形式的覆盖被允许的方式编写您的类。
因此,即使看起来我们在返回字段之前检查了该字段,我们也无法更改getTextfrom的返回值。String?Stringtextnull
- It seems odd to me that a fairly esoteric use case like overriding final in a sub-class, is now putting a big giant wart in NNBD implementations. Flutter layouts will be full of `!` each one creating a potential bug down the road, because the alternative is just too verbose.
-
Thanks @jamesdlin I believe that is actually the only safe way to work with this. But I think most devs will just use the ! operator, which then basically kills any advantage of NNBD for that var, and creates brittle methods that could easily be broken in the future.
eg; `if(index == null) return; index = index! + 1;` If someone later removes this null check, the compiler says nothing, and a grenade is sitting just there. In this example that looks a little silly, but on methods longer than a few lines, this is a significant issue, those `!` operators do not exactly jump out at the reader.