我已经启动了dart 2.8零安全实验.

我已经将我的应用程序转换为nullsaftey,但它使用的是旧的空安全包.

问题是旧的包有一个可以返回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.

鉴于所有的nullsaftey版本声明都说您可以对较旧的包使用nullsaftey,我猜有某种方法可以将导入的包声明为非nullsafe.

问题是我找不到任何关于如何做到这一点的文档.

推荐答案

null safety has not been released yet! that is why you need to provide the experiment flag.

语言版本控制

默认情况下,库中是否支持空安全由其语言版本决定.任何2.8或更低版本的语言都被视为 Select 退出空安全,2.9或更高版本(视情况而定)将被 Select 加入.语言版本本身可以来自以下两个地方之一:

  1. 包声明的SDK约束的最小界限.以下软件包的语言版本为2.8.

name: foo
env:
  sdk:
    ">=2.8.0 <3.0.0"
  1. 在任何其他声明之前,语言会覆盖文件顶层的注释.以下库的语言版本为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?.这是一个非常有效的类型注释,因为通常TT*总是可分配给T?.它也更正确,因为您知道API可以返回null.

String? home = env('HOME');
home ??= '/home';

编辑2021年6月:

零安全已释放,耶!默认情况下启用空安全的第一个DART版本最终是2.12,而不是上面问题中介绍的2.9.

Dart相关问答推荐

异类列表中函数类型不变性的解决方法

有什么区别!并且 ! 在 Dart 中?

禁用 ListView 滚动

Flutter:Firebase 基本查询或基本搜索代码

在polymer和dart中将内容标签渲染为模板的一部分

如何将 Dart 代码迁移到不可空 (NNBD)?

在 Dart 中,List.unmodifiable() 和 UnmodifiableListView 有什么不同?

找不到名为split-per-abi的选项

Flutter-创建一个倒计时(countdown)小部件

Flutter 在 main 中读取共享首选项,然后决定哪个启动页面?

在 Flutter 的 TextFormField 中管理事件

为什么 Dart 有编译时常量?

Dart 有小部件库吗?

如何循环遍历元素列表

如何在dart中获得一周的开始或结束

轻松判断数字是否在 Dart 的给定范围内?

如何在 Dart 中获取字符串的字节数?

学习 Dart 好还是我必须使用基本的 javascript?

使用 Dart 将 Uint8List 转换为字符串

Dart 中的错误与异常