null safety has not been released yet! that is why you need to provide the experiment flag.个
语言版本控制
默认情况下,库中是否支持空安全由其语言版本决定.任何2.8或更低版本的语言都被视为 Select 退出空安全,2.9或更高版本(视情况而定)将被 Select 加入.语言版本本身可以来自以下两个地方之一:
- 包声明的SDK约束的最小界限.以下软件包的语言版本为2.8.
name: foo
env:
sdk:
">=2.8.0 <3.0.0"
- 在任何其他声明之前,语言会覆盖文件顶层的注释.以下库的语言版本为2.8.
// @dart=2.8
class Foo {}
语言覆盖注释将优先于SDK约束,但仅在声明它的单个库中优先.
空安全代码和非空安全代码之间的交互
但是,如果没有不同的软件包或不正确的语言版本,问题是可以重现的,并且与空安全代码和非空安全代码之间的交互有关.考虑下面的例子:
// @dart=2.8
String foo() {
return null;
}
// @dart=2.9
import 'a.dart';
void main() {
var value = foo();
value ??= 'asd';
}
返回类型foo
不会变成String?
,而是被标记为String*
——这被称为遗留类型.A legacy type is treated as a non-null type in opted in libraries.遗留类型的目标是通过有序迁移更容易迁移到空安全性
// @dart=2.9
void foo(String value) {
// do something with non-null String.
}
// @dart=2.8
import 'a.dart';
void main() {
foo(getStringFromAPI());
}
虽然foo
需要一个非空字符串,但入口点实际上不可能传递一个,因为它还没有 Select 输入.如果不将遗留类型视为不可为null的类型,就不可能逐步迁移,因为所有库都需要一次更新,或者只更新为接受可为null的类型.
无序迁移
通过从空安全库调用尚未迁移到空安全的代码,增加了当该依赖项最终迁移时被 destruct 的风险.在您的示例中,如果home
被视为不可为空,则更新为具有更新返回值String?
的依赖项版本将导致编译错误.
对于您的具体情况,我建议特别将home
的类型注释为String?
.这是一个非常有效的类型注释,因为通常T
和T*
总是可分配给T?
.它也更正确,因为您知道API可以返回null.
String? home = env('HOME');
home ??= '/home';
编辑2021年6月:
零安全已释放,耶!默认情况下启用空安全的第一个DART版本最终是2.12
,而不是上面问题中介绍的2.9
.