26

我在 SO 帖子中看到了以下评论,我很感兴趣:

为什么不使用 if 进行空检查?a?.let{} ?: run{}仅在极少数情况下是合适的,否则它不是惯用的 — — voddan 2016 年 5 月 15 日在 7:29 在 kotlin 中进行空检查的最佳方法?

为什么该结构“仅适用于极少数情况”?
Kotlin 的首席工程师说,

run 允许您在 elvis 运算符的右侧使用多个语句 https://stackoverflow.com/a/51241983/6656019

尽管我承认这实际上并没有认可它是惯用的。这两个帖子似乎都来自备受尊敬的 SO Kotlin 贡献者。
激发原始评论的帖子提到,如果是可变let的,则表达式的一部分很重要。a在这种情况下,您需要a?.let{} ?: run{}代替if{} else {}.

我发现我喜欢“让猫王跑”的结构。在大多数情况下我应该避免它吗?
感谢您的任何见解。

4

2 回答 2

25

foo?.let { bar(it) } ?: baz()与.混为一谈是危险的if (foo != null) bar(foo) else baz()

假设您有一个功能:fun computeElements(): List<Int>? = emptyList()

考虑这段代码:

val maxElement = computeElements()?.let { it.max() } ?: return
println("Max element was $maxElement")

相比:

val list: List<Int>? = computeElements()
val maxElement = if (list != null) list.max() else return
println("Max element was $maxElement")

你可能认为这是两种等价的形式。但是,如果您同时运行两者,您会发现前者不会将任何内容打印到标准输出!

这是因为it.max()返回null一个空列表(因为没有最大元素),这导致 Elvis 表达式的右侧被计算,因此函数return提前。

简而言之,允许评估?.let { ... } ?: ... “if-else”的两个分支,这是危险的。除了这种形式不可读(if-else普遍理解,但let-run不是)之外,可能会出现细微的错误。

于 2019-03-12T16:49:09.957 回答
15

在这种情况下,您需要一个?.let{} ?: run{} 而不是 if{} else {}

不,您可以省略运行部分run { statement }并使用a?.let{} ?: statement.

在大多数情况下我应该避免它吗?

您应该在需要时使用它。例如,当您想在该场景中运行多个语句时。有人指出,这是一种罕见的情况。通常,您只会在 elvis 运算符的右侧看到一条语句。
当然,当你不需要它时不要使用它。保持代码简单。

于 2018-09-27T14:22:31.887 回答