菊花链 Elvis 运算符?

Daisy Chaining Elvis Operators?

这有点丑:

override var x1: Double = 0.0 //x-coordinate for object
    get() =
        if(hasParent) { //if there is no parent, we can't have an x coord anyway - nowhere to draw this object
            if (hasPrev) { //we won't always have a previous event, thus the other branch
                prev!!.x2 + parent!!.mEventSpacing
            } else {
                parent!!.mEventStartX
            }
        } else {
            field
        }

是否可以将其替换为类似下面的内容?

override var x1: Double = 0.0
    get() = (prev?.x2 + parent?.mEventSpacing) ?: parent?.mEventStartX ?: field

逻辑显然不对,但是有没有接近于此的东西?或者做这么简单的事情需要一些严肃的狂热吗?

假设 hasParent = parent != nullhasPrev = prev != null
还假设 parentprevifwhen 语句中定义为 val,而不是 var,因为我不喜欢添加!! 多次。

你正在做的是,使用 when 表达式:

override var x1: Double = 0.0 //x-coordinate for object
    get() = when {
        parent != null && prev != null -> prev.x2 + parent.mEventSpacing
        parent != null && prev == null -> parent.mEventSpacing
        parent == null -> field
    }

您可以使用 ?. 运算符和 let 函数的组合(请参阅 Safe Calls 部分):

override var x1: Double = 0.0 //x-coordinate for object
    get() =
        parent?.let { pr -> prev?.let { pv -> pv.x2 + pr.mEventSpacing } ?: pr.mEventSpacing } ?: field

let函数执行参数块let,return参数块中的最后一个表达式。

例如1.let { it + 2 }就是3.

如果 x 不为空,

x?.let 执行 let 函数。 即 x?.let { ... }if (x != null) x.let { ... } else null).

相同

这里,

如果parent == null,则
parent?.let { pr -> prev?.let { pv -> pv.x2 + pr.mEventSpacing } ?: pr.mEventSpacing } 只是 null.

如果parent != null,那么
parent?.let { pr -> prev?.let { pv -> pv.x2 + pr.mEventSpacing } ?: pr.mEventSpacing } 等同于 prev?.let { pv -> pv.x2 + parent!!.mEventSpacing } ?: parent!!.mEventSpacing

你可以缩短它。如果 prev == null,那么 prev.x2 可以被视为 0。所以

override var x1: Double = 0.0 //x-coordinate for object
    get() =
        parent?.let { pr -> (prev?.let { pv -> pv.x2 } ?: 0) + pr.mEventSpacing } ?: field

您可以在内部 let 函数中使用 it 进一步缩短它。

override var x1: Double = 0.0 //x-coordinate for object
    get() =
        parent?.let { pr -> (prev?.let { it.x2 } ?: 0) + pr.mEventSpacing } ?: field

此外,您可以使用 runlet 的组合。 (Google kotlin runkotlin run vs let 如果你不知道。)

override var x1: Double = 0.0 //x-coordinate for object
    get() =
        parent?.run { (prev?.let { it.x2 } ?: 0) + mEventSpacing } ?: field

不过我觉得用when是最容易理解的


嗯,如果 parentprev 被定义为 var,使用 when 表达式和 !! 可以引发 NPE,而使用 ?.let?.run?: 永远不会在多核设备中引发 NPE。为防止这种情况,您可以使用 getter 函数中的当前值定义局部 vals,这样您就永远不需要使用 !! 运算符。