Kotlin 多变量 let,在下一个 let 中使用前面的变量

Kotlin multiple variable let, using the previous variables in the next let

我希望能够有多个 let 并且下一个 let 能够使用前一个变量 只有 如果它不为空。我想要这个的原因是因为我只想要一个 :?对于所有的让。这可能吗?

关于我想要它的示例:

fun example() {
  firstVariable?.let a -> &&
  exampleFunction(a, 3)?.let { a, b ->
    // Use a and b freely since they are not null and not optionals
  } ?: run {
    // Runs if either one of the let is failing
  }
}

// a is NOT optional
fun exampleFunction(a: Int, b: Int?): Int? {
  if (b == null) {
    return null
  }

  return a + b
}

愚蠢的例子,但它只是为了展示我需要什么...我想检查第一个变量是否为 null 并且 运行 一个 returns 可选的函数可选参数,它是第一个变量 - 如果其中任何一个失败,我想 运行 其他东西。

我知道如何在没有 let 的情况下做到这一点,但我想知道是否有可能或计划能够做到这一点? (在 Swift 中是可能的)。

如何在Swift中做到:

// First check a, then use a in the same expression if its validated
if let a = firstVariable,
   let b = exampleFunction(a) {
  // Use a and b as non-optionals
} else {
  // a or b failed
}

您可以在 Kotlin 上受益并为您的案例编写一些扩展函数。 vararg 因为我们不知道要传递多少个变量,然后检查是否所有变量都不为空,如果是,return 所有变量。如果任何变量为空,则什么也不会发生。

fun <T: Any> multipleLetCheck(vararg variables: T?, block: (List<T>) -> Unit): Unit? {
    return if (variables.all { variable -> variable != null }) {
        block(variables.filterNotNull())
    } else {
        null
    }
}

// usage
multipleLetCheck(firstVariable, 3){ (firstVariable, secondVariable) ->
    // work with firstVariable and secondVariable
} ?: run {

}

您可能误解了 let 的工作原理。我要解释一下。简而言之,所需的行为在 kotlin 中是不可能的,或者至少你不能在没有任何缺点的情况下惯用地模仿它。

我不知道 swift 但似乎 let 使用的是语言本身提供的某种语法结构。它允许您定义一个具有某些 local 范围的变量,并且可以链接(如短路 &&)。

然而在 Kotlin 中 let 只是一个普通函数。 参见documentation。基本上无非就是

fun <T, R> T.let(block: (T) -> R): R = block(this)

它允许调用带有普通参数的函数作为带有 receiver type 的函数。

实际的 null 检查是使用 ?. 运算符完成的。 它采用 optional/nullable 值作为左侧操作数,或者短路 returning null 或调用右侧的函数,将非 null 左侧作为接收器类型。 let 只是这里可以调用的一个函数。 类似的 ?: 运算符采用 optional/nullable LHS 操作数和 returns 这个值(如果它不为空)或者它计算 RHS 上的表达式。

定义这些变量的一种方法是嵌套 lets:

firstVariable?.let{a -> exampleFunction(a, 3)?.let{b -> a + b}} ?: run{}

其中 a + b 只是使用这两个值的示例。但是,如果它长于一行,这将变得不方便。如果你仍然想定义局部变量,你可以用 run 创建一个块,并在 ?:

的右侧使用跳转语句
run {
    val a = firstValue ?: return@run null
    val b = exampleFunction(a, 3) ?: return@run null
    return@run a + b
} ?: run{}

虽然上面的代码看起来真的很难看 return@run null 重复,但可能有一些方法可以减少重复代码的数量,例如通过使用匿名函数(摆脱 @run 部分)或 return Unit 并使用一些副作用操作来保护最后一个值。 (去掉 null 和最后一个 return 语句)