Existe-t-il un moyen dans kotlin d'empêcher l'appel de fonction si tous les arguments (ou certains) sont nuls? Par exemple avoir la fonction:
fun test(a: Int, b: Int) { /* function body here */ }
Je voudrais empêcher les contrôles nuls dans le cas où les arguments sont null
. Par exemple, pour les arguments:
val a: Int? = null
val b: Int? = null
Je voudrais remplacer:
a?.let { b?.let { test(a, b) } }
avec:
test(a, b)
J'imagine que la syntaxe de définition de fonction pourrait ressembler à ceci:
fun test(@PreventNullCall a: Int, @PreventNullCall b: Int)
Et cela équivaudrait à:
fun test(a: Int?, b: Int?) {
if(a == null) {
return
}
if(b == null) {
return
}
// function body here
}
Est-ce que quelque chose comme ça (ou similaire) est possible pour réduire le code redondant de l'appelant (et éventuellement de l'auteur de la fonction)?
Si vous ne voulez pas que les appelants soient obligés de faire ces vérifications eux-mêmes, vous pouvez effectuer des vérifications nulles dans une fonction intermédiaire, puis faire appel à l'implémentation réelle quand ils ont réussi:
fun test(a: Int?, b: Int?) {
a ?: return
b ?: return
realTest(a, b)
}
private fun realTest(a: Int, b: Int) {
// use params
}
Edit: voici une implémentation de la fonction proposée par @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)
Bien sûr, vous devrez implémenter la fonction ifAllNonNull
pour 2, 3, etc. paramètres si vous avez d’autres fonctions pour lesquelles vous avez besoin de ses fonctionnalités.
Vous pouvez définir votre propre fonction inline pour cela.
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
Et puis vous pouvez l'appeler comme
ifNotNull(a, b, c, d) { a, b, c, d ->
...
}
NON! est la réponse à votre question (autant que je sache)
Votre meilleur pari (en supposant que la fonction n'est pas exposée) est ce que vous avez dit.
a?.let { b?.let { test(a, b) } }
Si la fonction est exposée et peut être appelée sans ces contrôles, vous devez alors placer les contrôles dans votre fonction.
fun test(a: Int?, b: Int?) {
if (listOf(a, b).filterNotNull().size < 2) return
println("Function was called")
}
Si vous essayez d’attribuer la valeur null à l’une des deux variables Int
, vous constaterez que cela ne fonctionne pas. Voir les erreurs de compilation dans les commentaires.
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?
}
L'exemple montre que, dans un monde pur de Kotlin, test(a: Int, b: Int)
ne peut pas être appelé avec les arguments null
ou même Int?
. Si vous mettez Java dans le mélange, je doute qu'il existe une solution sûre sans les contrôles null
, car vous pouvez appeler test(Int, Int)
avec le type Integer
du côté Java, qui autorise null. L'équivalent Java de Int
serait @NotNull Integer
(ce qui n'est pas vraiment null-safe).