我对Kotlin
很陌生,我试图弄清楚 Kotlin 的scope functions
。
我的代码如下所示:
with(something) {
when {
equals("test") -> var1 = "test123"
startsWith("test2") -> var2 = "test456"
contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
}
}
因此,在我使用.let
函数进行第三次检查之前,我的with
函数不需要详尽无遗(我不返回一些东西,我只是在做作业)。在我的第三次检查中,我使用.let
作为空检查......但仅适用于it.var3
的分配(如果不是null
)。当我知道 Kotlin 的.let
函数按标准返回正文的结果时,我不需要返回任何内容。
尽管如此,现在我的with/when
需要详尽无遗,否则它将无法再编译。
这让我思考并尝试了不同的东西。我找到了以下解决此问题的方法:
- 我可以在我的
with/when
中添加一个else
,这样它就变得详尽无遗,但实际上我不需要 else 并且我不想在这种情况下使用它。 - 我可以添加另一个
.let
,所以它看起来像这样:myNullableVar?.let { it.var3 = "test789" }.let{}
....但这对我来说看起来有点笨拙。它应该这样工作吗? - 使用
If(xy==null){...}else{...}
东西,但我认为我可以用不同的 Kotlin 解决这个问题
因为我是 Kotlin 的新手,所以我不确定如何正确处理这种情况。我可能会接受我的第二个想法,因为"它有效"。还是我不应该使用.let
进行空检查?添加另一个空 .let{}
?还是我根本没有得到零安全概念?我在这里感到有点迷茫。感谢您的任何帮助。
这似乎是一个不幸的功能组合......
仅当when
不返回值时,它才能不详尽。 问题是with()
函数确实返回了一个值。 由于when
位于底部,因此它的值就是返回的值,因此在这种情况下,它必须是详尽的。
那么,即使省略了"test3"分支,为什么它也不坚持使用else
分支呢? 这是因为赋值不会产生值。 (它们的计算结果为Unit
,这是 Kotlin 对不返回有用值的函数的特殊类型。 如果每个分支都给出Unit
,那么 Kotlin 似乎*很乐意推断一个默认分支也给出Unit
。
但是 "test3" 分支返回其他内容 —myNullableVar
的类型。 那么when
推断出什么类型呢? 该类型和Unit
最接近的公共超类型,它是顶级类型Any?
。现在它需要一个明确的else
分支!
那怎么办?
您已经找到了几个选项,但没有一个是理想的。 所以这里还有一些,同上!
-
您可以从该分支返回显式
Unit
:contains("test3") -> { myNullableVar?.let { it.var3 = "test789" }; Unit }
-
您可以从
with()
返回显式Unit
:contains("test3") -> myNullableVar?.let { it.var3 = "test789" } } Unit }
-
您可以为
with()
提供一个显式类型。 (它有两个类型参数,因此您需要同时提供这两个参数,从其参数的类型开始):with<String, Unit>("abc") {
恐怕我还没有找到一个明显的最佳答案......
回答你的最后一个问题:是的,?.let{
是完全惯用的,对于空检查来说很常见。 在这种特殊情况下,用if
替换它恰好可以解决类型问题:
contains("test3") -> { if (myNullableVar != null) myNullableVar.var3 = "test789" }
但是,除了冗长之外,如果myNullableVar
是一个属性而不是局部变量,那么它会打开一个竞争条件(如果另一个线程在测试和赋值之间将其设置为 null 怎么办?),所以编译器会抱怨——这正是人们使用let
的原因!
(* 我找不到这种行为的参考。 上面有官方的说法吗?