Функция вызова Kotlin, только если все аргументы не являются нулевыми - PullRequest
0 голосов
/ 07 июня 2018

Есть ли в kotlin способ предотвратить вызов функции, если все (или некоторые) аргументы равны нулю?Например Имея функцию:

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

Я хотел бы предотвратить проверки на ноль в случае, если аргументы null.Например, для аргументов:

val a: Int? = null
val b: Int? = null 

Я хотел бы заменить:

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

на:

test(a, b)

Я полагаю, что синтаксис определения функции может выглядеть как-токак это:

fun test(@PreventNullCall a: Int, @PreventNullCall b: Int)

И это будет эквивалентно:

fun test(a: Int?, b: Int?) {
    if(a == null) {
        return
    }

    if(b == null) {
        return
    }

    // function body here
}

Возможно ли что-то подобное (или подобное) уменьшить избыточный код вызывающего (и, возможно, автора функции) кода?

Ответы [ 5 ]

0 голосов
/ 16 апреля 2019

Let для кортежей (Pair & Triple)

Я думаю, что духом OP был синтаксис, поэтому мой ответ сосредоточен на предоставлении "let" для типов кортежей:

Пример использования:

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
}

Функции расширения:

// 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)
}

Вы можете заменить «на» другим словом (см. Руководство «Тройное расширение»), и вы можете расширить до более крупных кортежей (но Kotlin предоставляет только2 из коробки и, к сожалению, я не думаю, что это может быть общим).

0 голосов
/ 07 июня 2018

НЕТ!ответ на ваш вопрос (насколько я знаю)

Ваша лучшая ставка (при условии, что функция не выставлена) - это то, что вы сказали.

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

Если функция выставлена,и может быть вызван без этих проверок, тогда вам нужно поместить проверки внутри вашей функции.

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

    println("Function was called")
}
0 голосов
/ 07 июня 2018

Если вы не хотите, чтобы вызывающие абоненты сами выполняли эти проверки, вы можете выполнить нулевые проверки в промежуточной функции, а затем вызвать реальную реализацию, когда они прошли:

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

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

Редактировать: вот реализация функции, которую @Alexey Romanov предложил ниже:

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)

Конечно, вам нужно реализовать функцию ifAllNonNull для параметров 2, 3 и т. Д., Если у вас есть другие функциигде вам нужен его функционал.

0 голосов
/ 07 июня 2018

Вы можете определить свою собственную встроенную функцию для него.

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

И тогда вы можете назвать это как

ifNotNull(a, b, c, d) { a, b, c, d ->
    ...
}
0 голосов
/ 07 июня 2018

Если вы попытаетесь присвоить пустое значение любой из двух переменных Int, вы обнаружите, что это не работает.См. Ошибки компиляции в комментариях.

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?
}

Пример показывает, что в чистом котлинском мире test(a: Int, b: Int) нельзя вызывать с null или даже Int? аргументами.Если вы включите Java в смесь, я сомневаюсь, что есть безопасное решение без проверок null, потому что вы можете вызывать test(Int, Int) с типом Integer со стороны Java, что позволяет использовать null.Java, «эквивалентный» Int, будет @NotNull Integer (который на самом деле не является нулевым).

...