Kotlin 成语:空安全条件?
Kotlin idiom: null-safe conditional?
在Java中,我会这样写:
if (foo != null && foo.bar()) { ...
但是 Kotlin 抱怨说:
Smart cast to 'Foo' is impossible, because 'foo' is a mutable property that could have been changed by this time
我 认为 它说我写的不是线程安全的。但是,在我使用它的上下文中,我知道它是因为它将始终在单个线程上调用。
是 foo
需要可变。我意识到将 foo
设为 val
可以解决这个问题,但这在这里是不可能的。
Kotlin 中处理这种情况的正确习惯用法是什么?
诀窍是使用 Kotlin 的优秀 null-safety operators 来避免进行冗余检查。
首先,我们使用安全调用运算符。
foo?.bar()
这是一个 Boolean?
(即可为空的布尔值),如果 foo
为空,则为空,否则为 bar()
的结果。现在,Boolean?
显然不是 if 语句中的有效条件,因此我们需要提供 false
的“默认”值。我们使用名字有趣的 Elvis 运算符
来做到这一点
if (foo?.bar() ?: false) { ... }
如果foo
为空,则foo?.bar()
为空,?:
returns右侧的值,即false
。如果 foo
是非空的,那么 foo?.bar()
是在 foo
上调用 bar()
的结果,并且(假设结果也是非空的),?:
returns现有的非空布尔值。
在这种情况下,空安全调用 returns 布尔值?所以你可以检查它是否等于 true
:
if (foo?.bar() == true) {
}
如果条件语句中需要非空 foo
,则可以使用常见的 ?.let
惯用语。
foo?.let { foo ->
if (foo.bar()) {
}
}
如果您知道它只能在同一个线程上访问,则 !!
运算符在 null 检查后是安全的,但是 ?.let
更惯用,所以一旦您习惯了就更容易理解阅读 Kotlin。
如果条件不仅仅是函数调用,例如
foo != null && foo.bar() > 0
您可以使用 let
或 run
:
if (foo.let { it != null && it.bar() > 0 }) { ... }
if (foo.run { this != null && bar() > 0 }) { ... }
在Java中,我会这样写:
if (foo != null && foo.bar()) { ...
但是 Kotlin 抱怨说:
Smart cast to 'Foo' is impossible, because 'foo' is a mutable property that could have been changed by this time
我 认为 它说我写的不是线程安全的。但是,在我使用它的上下文中,我知道它是因为它将始终在单个线程上调用。
是 foo
需要可变。我意识到将 foo
设为 val
可以解决这个问题,但这在这里是不可能的。
Kotlin 中处理这种情况的正确习惯用法是什么?
诀窍是使用 Kotlin 的优秀 null-safety operators 来避免进行冗余检查。
首先,我们使用安全调用运算符。
foo?.bar()
这是一个 Boolean?
(即可为空的布尔值),如果 foo
为空,则为空,否则为 bar()
的结果。现在,Boolean?
显然不是 if 语句中的有效条件,因此我们需要提供 false
的“默认”值。我们使用名字有趣的 Elvis 运算符
if (foo?.bar() ?: false) { ... }
如果foo
为空,则foo?.bar()
为空,?:
returns右侧的值,即false
。如果 foo
是非空的,那么 foo?.bar()
是在 foo
上调用 bar()
的结果,并且(假设结果也是非空的),?:
returns现有的非空布尔值。
在这种情况下,空安全调用 returns 布尔值?所以你可以检查它是否等于 true
:
if (foo?.bar() == true) {
}
如果条件语句中需要非空 foo
,则可以使用常见的 ?.let
惯用语。
foo?.let { foo ->
if (foo.bar()) {
}
}
如果您知道它只能在同一个线程上访问,则 !!
运算符在 null 检查后是安全的,但是 ?.let
更惯用,所以一旦您习惯了就更容易理解阅读 Kotlin。
如果条件不仅仅是函数调用,例如
foo != null && foo.bar() > 0
您可以使用 let
或 run
:
if (foo.let { it != null && it.bar() > 0 }) { ... }
if (foo.run { this != null && bar() > 0 }) { ... }