1

我很新,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)。.let当我知道 Kotlin 的函数按标准返回正文的结果时,我不需要返回任何内容。

尽管如此,现在我with/when需要详尽无遗,否则它将不再编译。

这让我思考并尝试不同的事情。我找到了解决这个问题的这些方法:

  1. 我可以在elsemy中添加一个,with/when所以它变得详尽,但实际上我不需要 else,我不想在这种情况下使用它。
  2. 我可以添加另一个.let,所以它看起来像这样:myNullableVar?.let { it.var3 = "test789" }.let{}.... 但这对我来说看起来有点 hacky。它应该像这样工作吗?
  3. 使用If(xy==null){...}else{...}东西,但我认为我可以用 Kotlin 以不同的方式解决这个问题

因为我是 Kotlin 的新手,所以我不确定如何正确处理这种情况。我可能会选择我的第二个想法,因为“它有效”。还是我不应该.let用于空检查?添加另一个空的 . let{}? 还是我根本没有得到零安全概念?我觉得这里有点失落。谢谢你的帮助。

4

1 回答 1

3

这似乎是一个不幸的功能组合……</p>

仅当Awhen不返回值时,它才能是非穷尽的。问题是该with()函数确实返回了一个值。由于when在底部,它的值就是返回的值,所以在这种情况下它必须是详尽的。

else那么为什么即使你省略了“test3”分支,它也不坚持一个分支呢?那是因为赋值不会产生值。(它们评估为Unit,这是 Kotlin 的特殊类型,用于不返回有用值的函数。)如果每个分支都给出Unit,那么 Kotlin 似乎*很乐意推断默认分支也给出Unit

但是“test3”分支返回了别的东西—— myNullableVar. 那么when推断是什么类型呢?该类型最接近的公共超类型 and Unit,它是顶级类型Any?。现在它需要一个明确的分支else

那么该怎么办?

您已经找到了一些选项,但没有一个是理想的。所以这里还有一些,同上!

  • Unit您可以从该分支返回一个显式:

      contains("test3") -> { myNullableVar?.let { it.var3 = "test789" }; Unit }
    
  • 您可以Unit从以下返回显式with()

              contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
          }
          Unit
      }
    
  • 您可以为with(). (它有两个类型参数,所以你需要同时给出两个,从它的参数类型开始):

      with<String, Unit>("abc") {
    

恐怕我还没有找到一个明显的最佳答案……</p>

并回答您的最后一个问题:是的,?.let{对于空检查来说是完全惯用和常见的。在这种特殊情况下,将其替换为if恰好可以解决类型问题:

contains("test3") -> { if (myNullableVar != null) myNullableVar.var3 = "test789" }

但是除了冗长之外,如果myNullableVar是一个属性而不是一个局部变量,那么它会打开一个竞争条件(如果另一个线程在测试和赋值之间将它设置为 null 怎么办?)所以编译器会抱怨 -这正是人们使用它的原因let


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

于 2020-09-04T14:24:25.090 回答