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

时间:2019-09-04 11:30:56

标签: kotlin optional let

我希望能够有多个let,而下一个let只能使用前一个变量 (如果其不为null)。我想要这个的原因是因为我只想要一个:?所有的让。这可能吗?

关于我希望如何的示例:

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并运行一个函数,该函数返回带有第一个变量的非可选参数的可选变量-如果有在这些失败中,我想执行其他操作。

我知道如何做到这一点,但我想知道是否有可能或计划做到这一点? (在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
}

2 个答案:

答案 0 :(得分:1)

您可以从Kotlin上受益,并为您的案例编写扩展功能。 vararg,因为我们不知道要传递多少变量,然后检查所有变量是否都不为null,如果不是,则返回所有变量。如果任何变量为null,则什么都不会发生。

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 {

}

答案 1 :(得分:1)

您可能会误解了let的工作方式。我要解释一下。简而言之,在kotlin中无法实现所需的行为,或者至少您不能在没有任何缺点的情况下习惯地模仿它。

我不知道很快,但似乎let所使用的语言本身提供了某种语法构造。它使您可以定义具有某些 local 范围的变量,并且可以将其链接(例如短路&&)。

但是在Kotlin中,let只是一个正常功能。 请参见documentation。基本上无非是

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

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

实际的null检查是通过?.运算符完成的。 它接受一个可选/可为空的值作为左侧操作数,或者短路返回空值,或者在右侧使用非空左侧作为接收器类型调用该函数。 let只是在此处调用的一种可能函数。 相似的?:运算符采用可选的/可为空的LHS操作数,如果该值不为null或在RHS上计算表达式,则返回该值。

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

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部分)或返回Unit并通过一些副作用操作来保护最后一个值。 (以摆脱null和最后一个return语句)