使用 Kotlin 的作用域函数,而不是详尽无遗的 / 当



我对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需要详尽无遗,否则它将无法再编译。

这让我思考并尝试了不同的东西。我找到了以下解决此问题的方法:

  1. 我可以在我的with/when中添加一个else,这样它就变得详尽无遗,但实际上我不需要 else 并且我不想在这种情况下使用它。
  2. 我可以添加另一个.let,所以它看起来像这样:myNullableVar?.let { it.var3 = "test789" }.let{}....但这对我来说看起来有点笨拙。它应该这样工作吗?
  3. 使用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的原因!


(* 我找不到这种行为的参考。 上面有官方的说法吗?

最新更新