代码之家  ›  专栏  ›  技术社区  ›  Edward Brey

Kotlin中布尔条件、空检查和赋值的联合测试分支

  •  0
  • Edward Brey  · 技术社区  · 4 年前

    在Kotlin中,如何在多个条件上进行分支,这些条件都是延迟计算的,其中一些可能涉及变量赋值?

    int b;
    if (a > 0 && (b = getB()) > 0)
        branch1(a, b);
    else
        branch2();
    

    这里是一个Swift版本,假设返回是可以接受的。使用 Optional

    guard a > 0, let b = Optional(getB()), b > 0
        else { branch2(); return }
    branch1(a, b)
    

    在这些例子中, branch1 branch2 是用于解释目的的函数调用,但在实际使用中可能是内联代码。必须将代码分解成不同的方法可能是不可取的。

    与Swift一样,Kotlin的赋值不等于赋值。然而,Kotlin并没有直接等价于 guard

    0 回复  |  直到 4 年前
        1
  •  0
  •   gidds    4 年前

    最直接的翻译可能是:

    val a: A
    if (b && r != null && getA()?.also{ a = it } != null)
        branch1(b, r, a) // ERROR: Variable 'a' must be initialized
    else
        branch2()
    

    a 将始终按其在中使用的时间分配 branch1()

    你可以把它变成一个 var null ,这意味着使字段为空,然后必须添加 !! 当你使用它的时候。所有这一切使得它相当丑陋,即使条件是在一个地方,和 getA()

    var a: A? = null
    if (b && r != null && getA()?.also{ a = it } != null)
        branch1(b, r, a!!)
    else
        branch2()
    

    :

    val a = if (b && r != null) getA() else null
    if (a != null)
        branch1(b, r!!, a)
    else
        branch2()
    

    这是可行的,但现在编译器无法判断 r 为非null,因此需要 !! 而是那里。

    你可以用一个 when

    when (val a = if (b && r != null) getA() else null) {
        null -> branch2()
        else -> branch1(b, r!!, a)
    }
    

    然后 在条件和结果分支中使用这些副作用,这对人类和编译器来说都是一样令人困惑的(多年来,C一直是我的主要语言,我总是觉得嵌入的任务很尴尬)如果我看到这样的代码,我会考虑以更直接的方式重写它,以便维护它的人受益。在这种情况下,可能是:

    if (b && r != null) {
        val a = getA()
        if (a != null)
            branch1(b, r, a)
        else
            branch2()
    } else
        branch2()
    

    branch2() 调用(不过,如果调用非常复杂,可能会有其他方法,例如设置标志)。但可以说,这更容易理解(尤其是在看的时候) r 中不能为空 分支1()

    (顺便说一下,所有这些都假设 可能昂贵和/或有副作用;如果不是这样的话,就会有更简单的替代方案不必要地称之为。相反,如果需要多个作业,所有这些选项都会变得更复杂。)