将 if...else null 编写为 ?./?: 链的一部分的惯用 Kotlin 方式是什么?

What's the idiomatic Kotlin way to write `if...else null` as part of ?./?: chains?

(为清晰起见进行了编辑)

我一直发现自己在写 (if (x) f() else null) ?: (if (y) g() else null) ?: (if (z) h() else null) 和类似的东西,我确定我不是唯一一个人

我一直在寻找像下面定义的 valueIf 这样的函数(takeIf,参数的顺序颠倒了,所以值是惰性的),这样我就可以编写像 getViewEventType2() 而不是像 getViewEventType1() 这样的代码(都在下面详细说明)。

有没有我遗漏的成语?

(此外,编译器对这样的函数是否聪明,或者我是否应该担心创建太多临时闭包?)

    private fun getViewEventType1(): String? {
        return if (intent.action == "android.intent.action.VIEW") {
            intent.data?.pathSegments?.let {
                if (it.size == 3 && it[0] == "app" && it[1] == "event") it[2]
                else null
            }
        } else null
    }

    private fun getViewEventType2(): String? {
        return valueIf(intent.action == "android.intent.action.VIEW") {
            intent.data?.pathSegments?.let {
                valueIf(it.size == 3 && it[0] == "app" && it[1] == "event") { it[2] }
            }
        }
    }

    inline fun <T> valueIf(condition: Boolean, func: () -> T?) =
            if (condition) func() else null

您仍然可以使用 takeIf() 来实现您想要的,如 Intent 上的扩展函数所示:

fun Intent.getViewEventType(): String? {
    return takeIf { it.action == "android.intent.action.VIEW" }
        ?.`data`
        ?.pathSegments
        ?.takeIf { it.size == 3 && it[0] == "app" && it[1] == "event" }
        ?.get(2)
}

OP 编辑​​:这是我使用的最终代码:

fun getViewEventType(): String? {
    return intent.takeIf { it.action == "android.intent.action.VIEW" }
            ?.`data`
            ?.pathSegments
            ?.takeIf { it.size == 3 && it[0] == "app" && it[1] == "event" }
            ?.get(2)
}

: takeIf 所示,是构建此类结构的方法。

我会把剩下的留在这里给任何感兴趣的人(因为我的评论已经应用):你可能想省略 let 以支持 safe operator ?.. Additionally you may also be interested in destructing declarations,这使它成为在我看来更具可读性:

fun Intent.getViewEventType() : String? = takeIf { it.action == "android.intent.action.VIEW" }
        ?.`data`?.pathSegments
        ?.takeIf { it.size == 3 }
        ?.takeIf { (source, actionType) -> // destructuring in action... you may want to name the variables appropriately
            source == "app" && actionType == "event"
        }
        ?.get(2)

我在这里也使用了single expression function,但我把它留给你了。由于您在此处进行了很多链接,因此您可能至少希望在使用此类构造时指定 return 类型(您也可以省略)。