我已经启用了dart 2.8 nulsaftey实验。
我已经将我的应用程序转换为nulsaftey,但它使用了一个旧的nulsafety前包。
问题是旧包有一个可以返回null的方法:
/// Returns the environment variable with [name] or null if it doesn't
/// exist
String env(String name);
其用途如下:
var home = env('HOME');
如果HOME环境变量丢失,env
将返回null。
问题是env
被声明为返回String
。
所以当我写的时候
var home = env('HOME');
home ??= '/home';
我得到一个错误:
The operand can't be null, so the condition is always false.
Try removing the condition, an enclosing condition, or the whole conditional statement.
考虑到所有的nulsaftey发布公告都说你可以将nulsafte与旧的包一起使用,我猜有一些方法可以将导入的包声明为非nulsafe。
问题是我找不到任何关于如何做到这一点的文档。
空安全尚未发布!这就是为什么您需要提供实验标志
语言版本控制
默认情况下,库中是否支持null安全性取决于其语言版本。任何2.8或更低版本的语言都被视为选择退出零安全,2.9或更高版本(可能会更改(被选择加入。语言版本本身可以来自以下两个地方之一:
- 包声明的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*
——这被称为遗留类型在选择的库中,遗留类型被视为非null类型。遗留类型的目标是通过有序迁移更容易迁移到零安全考虑以下示例:
// @dart=2.9
void foo(String value) {
// do something with non-null String.
}
// @dart=2.8
import 'a.dart';
void main() {
foo(getStringFromAPI());
}
虽然foo
需要一个非空字符串,但入口点不可能实际传递一个,因为它还没有选择加入。如果不将遗留类型视为不可为null的类型,就不可能逐步迁移,因为所有库都需要一次更新,或者只更新为接受可为null类型。
无序迁移
通过调用尚未从空安全库迁移到空安全的代码,您增加了在依赖关系最终迁移时被破坏的风险。在您的示例中,如果home
被视为不可为null,那么更新到具有更新的返回值String?
的依赖项版本将导致编译错误。
对于您的特定情况,我建议将home
的类型特别注释为String?
。这是一个完全有效的类型注释,因为通常T
和T*
总是可分配给T?
。它也更正确,因为您知道API可以返回null。
String? home = env('HOME');
home ??= '/home';
2021年6月版:
零安全已经释放,耶!默认启用空安全的Dart的第一个版本最终是2.12
,而不是上面问题中所述的2.9
。