web-dev-qa-db-fra.com

Est-il possible d'utiliser la valeur par défaut sur un paramètre non facultatif lorsque la valeur null est passée?

Par exemple, si j'ai la classe de données suivante:

data class Data(
    val name: String = "",
    val number: Long = 0
)

Et les fonctions qui peuvent retourner null:

fun newName(): String? {}

fun newNumber(): Long? {}

Je sais que je peux utiliser ce qui suit pour utiliser la valeur des fonctions si elles ne sont pas null:

val newName = newName()
val newNumber = newNumber()

val data = Data(
        if (newName != null) newName else "",
        if (newNumber != null) newNumber else 0
)

Mais existe-t-il un moyen d'utiliser simplement la valeur par défaut spécifiée dans le constructeur de la classe Data lorsque les valeurs sont null?

Je n'ai rien trouvé dans la documentation, mais j'espérais que cela fonctionnerait:

val data = Data(newName()?, newNumber()?)

Mais cela ne compile pas.

29
Bryan

Vous pouvez créer un constructeur secondaire qui utilise les mêmes valeurs par défaut lors de la réception de null:

data class Data(
        val name: String = "",
        val number: Long = 0
) {
    constructor(
            name: String? = null,
            number: Long? = null
    ) : this(
            name ?: "",
            number ?: 0
    )
}
25
mfulton26

le constructeur secondaire ne prend en charge que les propriétés primitives Nullable. ce qui signifie qu'il en résultera 2 mêmes constructeurs si la propriété n'est pas un type primitif, par exemple:

data class Data(val name: String) {
    constructor(name: String? = null) : this(name ?: "foo");
    // ^--- report constructor signature error                
}

data class Data(val number: Long = 0) {
     constructor(number: Long? = null) : this(number ?: 0)
     //                  ^--- No problem since there are 2 constructors generated:
     //                       Data(long number) and Data(Java.lang.Long number)
}

une autre méthode consiste à utiliser l'opérateur invoke, par exemple:

data class Data(val name: String) {
    companion object {
        operator fun invoke(name: String? = null) = Data(name ?: "")
    }
}

SI la classe n'est pas une classe de données, vous pouvez initialiser en différé les propriétés à partir de paramètres, plutôt que de définir des propriétés sur le constructeur principal, par exemple:

class Data(name: String? = null, number: Long? = null) {
    val name = name ?: ""
    val number = number ?: 0
}
12
holi-java