Classes de données et classes scellées en Kotlin
Classes de données
Kotlin peut créer une classe qui ne contient que des données, avec le mot-clé :data:
data class User(val name: String, val age: Int)
Le compilateur extrait automatiquement les fonctions suivantes du constructeur primaire en fonction de toutes les propriétés déclarées :
-
equals()/hashCode() -
toString()Le format est le suivant :"User(name=John, age=42)" -
componentN() functionsCorrespond aux propriétés, organisées dans l'ordre de déclaration. -
copy()Fonctions
Si ces fonctions sont déjà explicitement définies dans la classe, ou héritées d'une superclasse, elles ne seront pas générées.
Pour garantir la cohérence et la pertinence du code généré, les classes de données doivent satisfaire aux conditions suivantes :
Le constructeur primaire doit contenir au moins un paramètre.
Tous les paramètres du constructeur primaire doivent être marqués comme
valouvar;Les classes de données ne peuvent pas être déclarées comme
abstract,open,sealedouinner;Les classes de données ne peuvent pas hériter d'autres classes (mais peuvent implémenter des interfaces).
Copy
La copie utilise la fonction copy(). Nous pouvons utiliser cette fonction pour copier un objet et modifier certaines propriétés. Pour la classe User ci-dessus, son implémentation ressemblerait à quelque chose comme ceci :
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
Exemple
Utilisez la classe copy pour copier la classe de données User et modifier la propriété age :
data class User(val name: String, val age: Int)
fun main(args: Array<String>) {
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
println(jack)
println(olderJack)
}
Le résultat de sortie est:
User(name=Jack, age=1) User(name=Jack, age=2)
Classes de données et déclarations de déstructuration
Les fonctions de composant permettent d'utiliser les classes de données dans les déclarations de déstructuration :
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
Classes de données standard
La bibliothèque standard fournitPairetTripleDans la plupart des cas, les classes de données nommées sont un meilleur choix de conception car elles rendent le code plus lisible et fournissent des noms et des propriétés significatifs.
Classes scellées
Les classes scellées sont utilisées pour représenter des structures d'héritage de classe restreintes : lorsqu'une valeur est d'un ensemble limité de types, et ne peut être d'aucun autre type. Dans un sens, elles sont des extensions des classes enum : l'ensemble des valeurs d'un type enum est également restreint, mais chaque constante enum n'existe que comme une instance unique, alors qu'une sous-classe d'une classe scellée peut avoir plusieurs instances qui peuvent contenir un état.
Pour déclarer une classe scellée, utilisezsealedpour modifier la classe. Les classes scellées peuvent avoir des sous-classes, mais toutes les sous-classes doivent être imbriquées à l'intérieur de la classe scellée.
sealed ne peut pas modifier une interface ou une classe abstraite (il signalera un avertissement, mais il n'y aura pas d'erreur de compilation).
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
Le principal avantage d'utiliser des classes sealed est que, lors de l'utilisation d'une expression when, si l'on peut vérifier que l'instruction couvre tous les cas, il n'est pas nécessaire d'ajouter une clause else à l'instruction.
fun eval(expr: Expr): Double = when(expr) {
is Expr.Const -> expr.number
is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
Expr.NotANumber -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
Autres extensions