迁移到 Dart 空安全:迁移三元运算符空检查的最佳实践? monadic 方法是否太不传统?

Migrating to Dart null safety: best practice for migrating ternary operator null checks? Is a monadic approach too unconventional?

我正在将一个代码库迁移到 null 安全,它包含很多这样的代码:

MyType convert(OtherType value) {
  return MyType(
    field1: value.field1,
    field2: value.field2 != null ? MyWrapper(value.field2) : null,
  );
}

不幸的是,三元运算符不支持带有 null 检查的类型提升,这意味着我必须添加 ! 来断言它不是 null,以便使其在 null 安全下编译:

MyType convert(OtherType value) {
  return MyType(
    field1: value.field1,
    field2: value.field2 != null ? MyWrapper(value.field2!) : null,
  );
}

这使得代码有点不安全;人们可以很容易地想象这样一个场景,其中空检查被修改或某些代码被复制并粘贴到 ! 导致崩溃的情况。

所以我的问题是是否有特定的最佳实践来更安全地处理这种情况?直接重写代码以利用流分析和类型提升是笨拙的:

MyType convert(OtherType value) {
  final rawField2 = value.field2;
  final MyWrapper? field2;
  if (rawField2 != null) {
    field2 = MyWrapper(rawField2);
  } else {
    field2 = null;
  }

  return MyType(
    field1: value.field1,
    field2: field2,
  );
}

作为一个在函数式编程方面思考很多的人,我的直觉是将可空类型视为 monad,并相应地定义 map

extension NullMap<T> on T? {
  U? map<U>(U Function(T) operation) {
    final value = this;
    if (value == null) {
      return null;
    } else {
      return operation(value);
    }
  }
}

那么这种情况可以这样处理:

MyType convert(OtherType value) {
  return MyType(
    field1: value.field1,
    field2: value.field2.map((f) => MyWrapper(f)),
  );
}

这似乎是保持安全性和简洁性的好方法。但是,我在网上搜索了很长时间,但找不到其他人在 Dart 中使用这种方法。有几个包示例定义了一个似乎早于空安全的 Optional monad,但我找不到任何 Dart 开发人员直接在可空类型上定义 map 的示例。这里有我遗漏的主要“问题”吗?在 Dart 中是否有另一种既符合人体工程学又更传统的方法?

Unfortunately, the ternary operator doesn't support type promotion with null checks

这个前提是不正确的。三元运算符 做类型提升。但是,无法提升non-local变量。另见:

因此您应该只引入一个局部变量(您似乎已经在 if-elseNullFlatMap 示例中实现):

MyType convert(OtherType value) {
  final field2 = value.field2;
  return MyType(
    field1: value.field1,
    field2: field2 != null ? MyWrapper(field2) : null,
  );
}