迁移到 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
-else
和 NullFlatMap
示例中实现):
MyType convert(OtherType value) {
final field2 = value.field2;
return MyType(
field1: value.field1,
field2: field2 != null ? MyWrapper(field2) : null,
);
}
我正在将一个代码库迁移到 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
-else
和 NullFlatMap
示例中实现):
MyType convert(OtherType value) {
final field2 = value.field2;
return MyType(
field1: value.field1,
field2: field2 != null ? MyWrapper(field2) : null,
);
}