Kotlin call function only if all arguments are not null

本秂侑毒 提交于 2019-12-01 15:55:43

You could define your own inline function for it.

inline fun <R, A> ifNotNull(a: A?, block: (A) -> R): R? =
    if (a != null) {
        block(a)
    } else null

inline fun <R, A, B> ifNotNull(a: A?, b: B?, block: (A, B) -> R): R? =
    if (a != null && b != null) {
        block(a, b)
    } else null

inline fun <R, A, B, C> ifNotNull(a: A?, b: B?, c: C?, block: (A, B, C) -> R): R? =
    if (a != null && b != null && c != null) {
        block(a, b, c)
    } else null

inline fun <R, A, B, C, D> ifNotNull(a: A?, b: B?, c: C?, d: D?, block: (A, B, C, D) -> R): R? =
    if (a != null && b != null && c != null && d != null) {
        block(a, b, c, d)
    } else null

And then you can call it like

ifNotNull(a, b, c, d) { a, b, c, d ->
    ...
}
zsmb13

If you don't want callers to have to do these checks themselves, you could perform null checks in an intermediary function, and then call into the real implementation when they passed:

fun test(a: Int?, b: Int?) {
    a ?: return
    b ?: return
    realTest(a, b)
}

private fun realTest(a: Int, b: Int) {
    // use params
}

Edit: here's an implementation of the function @Alexey Romanov has proposed below:

inline fun <T1, T2, R> ifAllNonNull(p1: T1?, p2: T2?, function: (T1, T2) -> R): R? {
    p1 ?: return null
    p2 ?: return null
    return function(p1, p2)
}

fun test(a: Int, b: Int) {
    println("$a, $b")
}

val a: Int? = 10
val b: Int? = 5
ifAllNonNull(a, b, ::test)

Of course you'd need to implement the ifAllNonNull function for 2, 3, etc parameters if you have other functions where you need its functionality.

NO! is the answer to your question(as far as I know)

Your best bet(assuming the function is not exposed) is what you said.

a?.let { b?.let { test(a, b) } }

If the function is exposed, and might be called without these checks, then you need to put the checks inside your function.

fun test(a: Int?, b: Int?) {
    if (listOf(a, b).filterNotNull().size < 2) return

    println("Function was called")
}

If you try assigning null to any of the two Int variables you will find that this doesn`t work. See the compile errors in the comments.

fun test(a: Int, b: Int) { /* function body here */ }

fun main(){
    test(null, 0) //Null can not be value of non-null type Int
    val b : Int? = null
    test(0, b) // Type mismatch. Required: Int - Found: Int?
}

The example shows that in a pure Kotlin world test(a: Int, b: Int) cannot be called with null or even Int? arguments. If you put Java in the mix I doubt there is a safe solution without null checks, because you can call test(Int, Int) with type Integer from the Java side, which allows null. The Java "equivalent" to Int would be @NotNull Integer (which is not really null-safe).

Let for Tuples (Pair & Triple)

I think the spirit of the OP was syntax, so my answer focuses on providing "let" for tuple types:

Example use:

fun main() {
    val p1: Int? = 10 // or null
    val p2: Int? = 20 // or null
    val p3: Int? = 30 // or null

    val example1 = (p1 to p2).let(::testDouble)
    val example2 = (p1 to p2).let { a, b -> a * b }

    val example3 = (p1 to p2 to p3).let(::testTriple)
    val example4 = (p1 to p2 to p3).let { a, b, c -> a * b * c }
}

fun testDouble(a: Int, b: Int): Int {
    return a + b
}

fun testTriple(a: Int, b: Int, c: Int): Int {
    return a + b + c
}

Extension Funs:

// Define let for Pair & Triple
fun <P1, P2, R> Pair<P1?, P2?>.let(f: (P1, P2) -> R): R? {
    return f(first ?: return null, second ?: return null)
}

fun <P1, P2, P3, R> Triple<P1?, P2?, P3?>.let(f: (P1, P2, P3) -> R): R? {
    return f(first ?: return null, second ?: return null, third ?: return null)
}

// Cute "to" syntax for Triple
infix fun <P1, P2, P3> Pair<P1?, P2?>.to(third: P3?): Triple<P1?, P2?, P3?> {
    return Triple(first, second, third)
}

You can replace "to" with another word (see Triple extension as a guide), and you could extend to larger tuples (but Kotlin only provides 2 out-of-the-box & sadly I don't think it can be generic).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!