【问题标题】:Kotlin multiple variable let, using the previous variables in the next letKotlin 多变量 let,在下一个 let 中使用前面的变量
【发布时间】:2019-09-04 11:30:56
【问题描述】:

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

我想要的示例:

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
}

愚蠢的例子,但它只是为了展示我需要什么......我想检查第一个变量是否为空并运行一个函数,该函数返回一个带有非可选参数的可选函数,该参数是第一个变量 - 如果有的话其中一个失败,我想运行其他东西。

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

【问题讨论】:

  • 我相信目前还没有这样的功能,但如果你满意,你可以随时创建自己的扩展功能
  • 我不确定如何编写这样的函数。你能举个例子吗? :)
  • @Eugene 该链接不能解决我的问题,因为下一个让不能使用第一个结果(正如我在那里评论的那样)。如前所述:示例函数很愚蠢,但只是为了证明我的观点。
  • 不能解决我的问题。只有当第一个变量不为空时,我才想使用第一个变量的结果。
  • @Eugene 更新了问题,让我更清楚我想做什么。

标签: kotlin optional let


【解决方案1】:

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

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

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

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

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

实际的空值检查是使用?. 运算符完成的。 它将一个可选/可为空的值作为左侧操作数,并且短路返回 null 或调用右侧的函数,将非空左侧作为接收器类型。 let 只是在这里调用的一个可能的函数。 类似的?: 运算符采用可选/可为空的 LHS 操作数,如果它不为空或计算 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 repititions,但可能有一些方法可以减少重复代码的数量,例如通过使用匿名函数(摆脱@run 部分)或返回Unit 并使用一些副作用操作来保护最后一个值。 (去掉null 和最后一个return 语句)

【讨论】:

  • 感谢您的出色回答。我知道 let 本身不可能做到这一点,我想知道是否可以通过其他方式实现。你用 run's 的方式解决了这个问题。 (是的,它很丑,但它正是我正在寻找的功能!)也许更好的方法将成为未来的一个功能。 :)
【解决方案2】:

您可以从 Kotlin 中受益,并为您的案例编写一些扩展功能。 vararg 因为我们不知道要传递多少个变量,然后检查它们是否都不为空,如果是,则返回所有变量。如果任何 var 为 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 {

}

【讨论】:

  • 这很好,但它不能解决我的问题:我只想在第一个变量不为空的情况下运行一个函数。
  • 我也希望 let's 的返回值能够有不同的类型
  • block(variables.filterNotNull()) filternotnull 此处不需要,因为您的 .all{}
  • all{} 返回数组而不是列表
  • 我不确定我是否得到你@Otziii,但请参阅编辑。现在,如果任何变量为空,则 run{} 将执行。这就是你想要的?
猜你喜欢
  • 2016-06-01
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
相关资源
最近更新 更多