Dart null / false / empty checking:如何写得更短?
Dart null / false / empty checking: How to write this shorter?
这是我的代码,除了空字符串、null 和 false 之外的所有内容都为真:
if (routeinfo["no_route"] == "" || routeinfo["no_route"] == null || routeinfo["no_route"] == false) {
// do sth ...
}
这是我的代码,除了空字符串、null、false 或零之外的所有内容都为真:
if (routeinfo["no_route"] == "" || routeinfo["no_route"] == null || routeinfo["no_route"] == false || routeinfo["no_route"] == 0) {
// do sth...
}
如何在 Dart 中写得更短?还是不可能?
你可以
if (["", null, false, 0].contains(routeinfo["no_route"])) {
// do sth
}
我会编写一个辅助函数,而不是内联处理所有内容。
bool isNullEmptyOrFalse(Object o) =>
o == null || false == o || "" == o;
bool isNullEmptyFalseOrZero(Object o) =>
o == null || false == o || 0 == o || "" == o;
这避免了重复查找(如 contains
操作),但它的可读性更高。它也不会为每个检查创建一个新的 List
文字(使列表 const 可以解决这个问题)。
if (isNullEmptyOrFalse(routeinfo["no_route"])) { ... }
当努力使一些东西变得简短易读时,制作一个名字恰当的辅助函数通常是最好的解决方案。
(补充:既然Dart有了扩展方法,就可以将功能添加为看似对象上的方法或getter,所以你可以直接写value.isNullOrEmpty
)。
如果您的要求只是空的或 null(就像我在搜索结果中看到这个标题时的要求),您可以使用 Dart 的安全导航运算符使其更简洁:
if (routeinfo["no_route"]?.isEmpty ?? true) {
//
}
在哪里
isEmpty
检查一个空字符串,但是如果 routeinfo 是 null
你不能在 null 上调用 isEmpty,所以我们用 检查 null
?.
safe navigation operator 仅当 object 不为 null 时才调用 isEmpty,否则生成 null。所以我们只需要用 检查 null
??
null coalescing operator
如果您的地图是可空类型,那么您必须安全地导航:
if (routeinfo?["no_route"]?.isEmpty ?? true) {
//
}
来自 Android 和 Kotlin,我更喜欢扩展方法而不是静态辅助方法。在 Dart 2.7 中,您现在也可以使用它:
extension Extension on Object {
bool isNullOrEmpty() => this == null || this == '';
bool isNullEmptyOrFalse() => this == null || this == '' || !this;
bool isNullEmptyZeroOrFalse() =>
this == null || this == '' || !this || this == 0;
}
现在您可以从代码中的任何位置调用这些方法:
if (anyVariable.isNullOrEmpty()) {
// do something here
}
您可能需要手动导入 dart class,在其中放置您的扩展方法,例如:
import 'package:sampleproject/utils/extensions.dart';
2020 年末更新
总结
- 除
isNull
和 isNotNull
外,此答案成立。将来 dart/flutter 中引入 Null Safety
时,它们不再提供类型提升。
- 像
isNullOrEmpty
这样的其他助手不提供类型提升,因为与调用站点相比,它们处于不同的(子)范围。
- 我个人的意见是,您可以放弃
isNull
和 isNotNull
,但保留其他助手,因为您不应该指望他们为您做类型提升。
说明
- 这是因为
Null Safety
终于在Dart/Flutter中引入了。但截至 2020 年 10 月,此功能仍不适用于 dart/flutter 上的稳定版本。查看快速指南 Null Safety or the thorough Understanding Null Safety.
- Dart/Flutter 中的 Null Safety 应该类似于 Swift (Optional) and Kotlin (Nullable Types, Non-Nullable Types)。
示范[=77=]
这里演示一下为什么encapsulation/helper-getter of isNull
(== null
)和isNotNull
(!= null
)是个很大的问题:
// Promotion works
int definitelyInt(int? aNullableInt) {
if (aNullableInt == null) { // Promote variable `aNullableInt` of Nullable type `int?` to Non-Nullable type `int`
return 0;
}
return aNullableInt; // Can't be null! This variable is promoted to non-nullable type `int`
}
当您使用的 dart 版本中包含“Null Safety”时,上述代码中的类型提升有效!然而:
// Promotion does NOT work!!!
int definitelyInt(int? aNullableInt) {
if (aNullableInt.isNull) { // does NOT promote variable `aNullableInt` of Nullable type `int?`
return 0;
}
return aNullableInt; // This variable is still of type `int?`!!!
}
以上不起作用,因为空检查 == null
和 != null
被封装在一个子范围(不同的堆栈框架)中,并且没有推断出在其中具有这种“提升”效果definitelyInt
范围。
2020 年初更新
这是一个修改版本,使用 getters 而不是 instance/class 方法 并覆盖 whitespaces、isNull 和 isNotNull.
第二次更新
它现在还可以计算空列表和地图!
第三次更新
为了安全和 modularity/maintainability 添加了私有 getter。
第四次更新
更新了解决 Map
的特定问题的答案,当它为空时无法正确处理!因为 Map
不是 Iterable
。通过引入 _isMapObjectEmpty
U
解决了这个问题
解决方案
extension TextUtilsStringExtension on String {
/// Returns true if string is:
/// - null
/// - empty
/// - whitespace string.
///
/// Characters considered "whitespace" are listed [here](
bool get isNullEmptyOrWhitespace =>
this == null || this.isEmpty || this.trim().isEmpty;
}
/// - [isNullOrEmpty], [isNullEmptyOrFalse], [isNullEmptyZeroOrFalse] are from [this Whosebug answer](
extension GeneralUtilsObjectExtension on Object {
/// Returns true if object is:
/// - null `Object`
bool get isNull => this == null;
/// Returns true if object is NOT:
/// - null `Object`
bool get isNotNull => this != null;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`s
/// - empty `Iterable` (list, set, ...)
/// - empty `Map`
bool get isNullOrEmpty =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`
/// - empty `Iterable` (list, map, set, ...)
/// - false `bool`
bool get isNullEmptyOrFalse =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty ||
_isBoolObjectFalse;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`
/// - empty `Iterable` (list, map, set, ...)
/// - false `bool`
/// - zero `num`
bool get isNullEmptyFalseOrZero =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty ||
_isBoolObjectFalse ||
_isNumObjectZero;
// ------- PRIVATE EXTENSION HELPERS -------
/// **Private helper**
///
/// If `String` object, return String's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `String`
bool get _isStringObjectEmpty =>
(this is String) ? (this as String).isEmpty : false;
/// **Private helper**
///
/// If `Iterable` object, return Iterable's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `Iterable`
bool get _isIterableObjectEmpty =>
(this is Iterable) ? (this as Iterable).isEmpty : false;
/// **Private helper**
///
/// If `Map` object, return Map's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `Map`
bool get _isMapObjectEmpty => (this is Map) ? (this as Map).isEmpty : false;
/// **Private helper**
///
/// If `bool` object, return `isFalse` expression
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `bool`
bool get _isBoolObjectFalse =>
(this is bool) ? (this as bool) == false : false;
/// **Private helper**
///
/// If `num` object, return `isZero` expression
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `num`
bool get _isNumObjectZero => (this is num) ? (this as num) == 0 : false;
}
假设
这里假设 Dart 2.7 或更高版本支持 Extension Methods。
用法
以上是两个分机类。一份用于 Object
,一份用于 String
。将它们放入文件 separately/together 并在调用站点文件中导入 files/file。
描述
来自 Swift,我倾向于使用像用户 @Benjamin Menrad 的 这样的扩展,但在适用时使用 getter 而不是 method/function —— 反映 Dart 的计算属性像 String.isEmpty
.
来自 C#,我喜欢他们的 String 辅助方法 IsNullOrWhiteSpace。
我的版本融合了以上两个概念。
命名
重命名扩展 类 任意名称。我倾向于这样命名它们:
XYExtension
其中:
- X 是 File/Author/App/Unique 名字。
- Y 是要扩展的类型的名称。
名称示例:
MyAppIntExtension
DartDoubleExtension
TextUtilsStringExtension
OHProviderExtension
批评
Why private getters instead of simple
this == null || this == '' || this == [] || this == 0 || !this
- 我认为这更安全,因为它首先将对象转换为我们要将其值与之进行比较的正确类型。
- 更加模块化,因为更改是私有 getter 的核心,任何修改都会反映到各处。
- 如果类型检查在私有 getter 中失败,我们 return false 这不会影响根逻辑或表达式的结果。
package:quiver
has an isEmpty
函数表示 returns true
如果参数是 null
或空字符串。
自己实现这样的功能也很简单
具有 Null 安全性:
假设,您有一个可为空的 Map
和一个 List
,其中包含可为空的值。
Map<String, List?>? map;
List<String?>? list;
要检查 null
、空和 false
,您可以这样做:
if (map?['key']?.isEmpty ?? false) {...}
if (list?[0]?.isEmpty ?? false) {...}
bool isNullString(String? value) {
if (value == null || value.isEmpty || value == false) {
return true;
} else {
return false;
}
}
并像
一样使用这种方法
isNullString(yourValue)
这是我的代码,除了空字符串、null 和 false 之外的所有内容都为真:
if (routeinfo["no_route"] == "" || routeinfo["no_route"] == null || routeinfo["no_route"] == false) {
// do sth ...
}
这是我的代码,除了空字符串、null、false 或零之外的所有内容都为真:
if (routeinfo["no_route"] == "" || routeinfo["no_route"] == null || routeinfo["no_route"] == false || routeinfo["no_route"] == 0) {
// do sth...
}
如何在 Dart 中写得更短?还是不可能?
你可以
if (["", null, false, 0].contains(routeinfo["no_route"])) {
// do sth
}
我会编写一个辅助函数,而不是内联处理所有内容。
bool isNullEmptyOrFalse(Object o) =>
o == null || false == o || "" == o;
bool isNullEmptyFalseOrZero(Object o) =>
o == null || false == o || 0 == o || "" == o;
这避免了重复查找(如 contains
操作),但它的可读性更高。它也不会为每个检查创建一个新的 List
文字(使列表 const 可以解决这个问题)。
if (isNullEmptyOrFalse(routeinfo["no_route"])) { ... }
当努力使一些东西变得简短易读时,制作一个名字恰当的辅助函数通常是最好的解决方案。
(补充:既然Dart有了扩展方法,就可以将功能添加为看似对象上的方法或getter,所以你可以直接写value.isNullOrEmpty
)。
如果您的要求只是空的或 null(就像我在搜索结果中看到这个标题时的要求),您可以使用 Dart 的安全导航运算符使其更简洁:
if (routeinfo["no_route"]?.isEmpty ?? true) {
//
}
在哪里
isEmpty
检查一个空字符串,但是如果 routeinfo 是null
你不能在 null 上调用 isEmpty,所以我们用 检查 null
?.
safe navigation operator 仅当 object 不为 null 时才调用 isEmpty,否则生成 null。所以我们只需要用 检查 null
??
null coalescing operator
如果您的地图是可空类型,那么您必须安全地导航:
if (routeinfo?["no_route"]?.isEmpty ?? true) {
//
}
来自 Android 和 Kotlin,我更喜欢扩展方法而不是静态辅助方法。在 Dart 2.7 中,您现在也可以使用它:
extension Extension on Object {
bool isNullOrEmpty() => this == null || this == '';
bool isNullEmptyOrFalse() => this == null || this == '' || !this;
bool isNullEmptyZeroOrFalse() =>
this == null || this == '' || !this || this == 0;
}
现在您可以从代码中的任何位置调用这些方法:
if (anyVariable.isNullOrEmpty()) {
// do something here
}
您可能需要手动导入 dart class,在其中放置您的扩展方法,例如:
import 'package:sampleproject/utils/extensions.dart';
2020 年末更新
总结
- 除
isNull
和isNotNull
外,此答案成立。将来 dart/flutter 中引入Null Safety
时,它们不再提供类型提升。 - 像
isNullOrEmpty
这样的其他助手不提供类型提升,因为与调用站点相比,它们处于不同的(子)范围。 - 我个人的意见是,您可以放弃
isNull
和isNotNull
,但保留其他助手,因为您不应该指望他们为您做类型提升。
说明
- 这是因为
Null Safety
终于在Dart/Flutter中引入了。但截至 2020 年 10 月,此功能仍不适用于 dart/flutter 上的稳定版本。查看快速指南 Null Safety or the thorough Understanding Null Safety. - Dart/Flutter 中的 Null Safety 应该类似于 Swift (Optional) and Kotlin (Nullable Types, Non-Nullable Types)。
示范[=77=]
这里演示一下为什么encapsulation/helper-getter of isNull
(== null
)和isNotNull
(!= null
)是个很大的问题:
// Promotion works
int definitelyInt(int? aNullableInt) {
if (aNullableInt == null) { // Promote variable `aNullableInt` of Nullable type `int?` to Non-Nullable type `int`
return 0;
}
return aNullableInt; // Can't be null! This variable is promoted to non-nullable type `int`
}
当您使用的 dart 版本中包含“Null Safety”时,上述代码中的类型提升有效!然而:
// Promotion does NOT work!!!
int definitelyInt(int? aNullableInt) {
if (aNullableInt.isNull) { // does NOT promote variable `aNullableInt` of Nullable type `int?`
return 0;
}
return aNullableInt; // This variable is still of type `int?`!!!
}
以上不起作用,因为空检查 == null
和 != null
被封装在一个子范围(不同的堆栈框架)中,并且没有推断出在其中具有这种“提升”效果definitelyInt
范围。
2020 年初更新
这是一个修改版本,使用 getters 而不是 instance/class 方法 并覆盖 whitespaces、isNull 和 isNotNull.
第二次更新
它现在还可以计算空列表和地图!
第三次更新
为了安全和 modularity/maintainability 添加了私有 getter。
第四次更新
更新了解决 Map
的特定问题的答案,当它为空时无法正确处理!因为 Map
不是 Iterable
。通过引入 _isMapObjectEmpty
U
解决方案
extension TextUtilsStringExtension on String {
/// Returns true if string is:
/// - null
/// - empty
/// - whitespace string.
///
/// Characters considered "whitespace" are listed [here](
bool get isNullEmptyOrWhitespace =>
this == null || this.isEmpty || this.trim().isEmpty;
}
/// - [isNullOrEmpty], [isNullEmptyOrFalse], [isNullEmptyZeroOrFalse] are from [this Whosebug answer](
extension GeneralUtilsObjectExtension on Object {
/// Returns true if object is:
/// - null `Object`
bool get isNull => this == null;
/// Returns true if object is NOT:
/// - null `Object`
bool get isNotNull => this != null;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`s
/// - empty `Iterable` (list, set, ...)
/// - empty `Map`
bool get isNullOrEmpty =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`
/// - empty `Iterable` (list, map, set, ...)
/// - false `bool`
bool get isNullEmptyOrFalse =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty ||
_isBoolObjectFalse;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`
/// - empty `Iterable` (list, map, set, ...)
/// - false `bool`
/// - zero `num`
bool get isNullEmptyFalseOrZero =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty ||
_isBoolObjectFalse ||
_isNumObjectZero;
// ------- PRIVATE EXTENSION HELPERS -------
/// **Private helper**
///
/// If `String` object, return String's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `String`
bool get _isStringObjectEmpty =>
(this is String) ? (this as String).isEmpty : false;
/// **Private helper**
///
/// If `Iterable` object, return Iterable's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `Iterable`
bool get _isIterableObjectEmpty =>
(this is Iterable) ? (this as Iterable).isEmpty : false;
/// **Private helper**
///
/// If `Map` object, return Map's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `Map`
bool get _isMapObjectEmpty => (this is Map) ? (this as Map).isEmpty : false;
/// **Private helper**
///
/// If `bool` object, return `isFalse` expression
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `bool`
bool get _isBoolObjectFalse =>
(this is bool) ? (this as bool) == false : false;
/// **Private helper**
///
/// If `num` object, return `isZero` expression
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `num`
bool get _isNumObjectZero => (this is num) ? (this as num) == 0 : false;
}
假设
这里假设 Dart 2.7 或更高版本支持 Extension Methods。
用法
以上是两个分机类。一份用于 Object
,一份用于 String
。将它们放入文件 separately/together 并在调用站点文件中导入 files/file。
描述
来自 Swift,我倾向于使用像用户 @Benjamin Menrad 的 String.isEmpty
.
来自 C#,我喜欢他们的 String 辅助方法 IsNullOrWhiteSpace。
我的版本融合了以上两个概念。
命名
重命名扩展 类 任意名称。我倾向于这样命名它们:
XYExtension
其中:
- X 是 File/Author/App/Unique 名字。
- Y 是要扩展的类型的名称。
名称示例:
MyAppIntExtension
DartDoubleExtension
TextUtilsStringExtension
OHProviderExtension
批评
Why private getters instead of simple
this == null || this == '' || this == [] || this == 0 || !this
- 我认为这更安全,因为它首先将对象转换为我们要将其值与之进行比较的正确类型。
- 更加模块化,因为更改是私有 getter 的核心,任何修改都会反映到各处。
- 如果类型检查在私有 getter 中失败,我们 return false 这不会影响根逻辑或表达式的结果。
package:quiver
has an isEmpty
函数表示 returns true
如果参数是 null
或空字符串。
自己实现这样的功能也很简单
具有 Null 安全性:
假设,您有一个可为空的 Map
和一个 List
,其中包含可为空的值。
Map<String, List?>? map;
List<String?>? list;
要检查 null
、空和 false
,您可以这样做:
if (map?['key']?.isEmpty ?? false) {...}
if (list?[0]?.isEmpty ?? false) {...}
bool isNullString(String? value) {
if (value == null || value.isEmpty || value == false) {
return true;
} else {
return false;
}
}
并像
一样使用这种方法isNullString(yourValue)