Clases de datos y clases selladas de Kotlin
clase de datos
Kotlin puede crear una clase que solo contenga datos; la palabra clave esdata:
data class User(val name: String, val age: Int)
El compilador extrae automáticamente las siguientes funciones del constructor principal en función de todas las propiedades declaradas:
-
equals()/hashCode() -
toString()Formato como"User(name=John, age=42)" -
componentN() functionsCorresponden a las propiedades, en orden de declaración -
copy()Función
Si estas funciones ya están definidas explícitamente en la clase, o se heredan de una superclase, no se generarán.
Para garantizar la coherencia y el significado del código generado, las clases de datos deben cumplir las siguientes condiciones:
El constructor primario debe contener al menos un parámetro.
Todos los parámetros del constructor principal deben marcarse como
valovar;Las clases de datos no pueden declararse como
abstract,open,sealedoinner;Las clases de datos no pueden heredar de otras clases (pero pueden implementar interfaces).
Copiar
Copia: usando la función copy(), podemos copiar un objeto y modificar algunas propiedades. Para la clase User anterior, su implementación sería similar a la siguiente:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
Ejemplos
Usando copy para copiar la clase de datos User y modificar la propiedad 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)
}
El resultado de salida es:
User(name=Jack, age=1) User(name=Jack, age=2)
Clases de datos y declaraciones de desestructuración
Las funciones de componente permiten que las clases de datos se usen en declaraciones de desestructuración:
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
clase de datos estándar
La biblioteca estándar proporcionaPairyTripleEn la mayoría de los casos, nombrar las clases de datos es una mejor opción de diseño, porque así el código es más legible y proporciona nombres y propiedades significativos.
clase sellada
Las clases selladas se usan para representar estructuras de herencia restringidas: cuando un valor tiene un número limitado de tipos y no puede tener ningún otro tipo. En cierto sentido, son una extensión de las clases de enumeración: el conjunto de valores de un tipo de enumeración también es limitado, pero cada constante de enumeración existe solo como una instancia, mientras que una subclase de una clase sellada puede tener varias instancias que pueden contener estado.
Para declarar una clase sellada, usasealedClase modificadora: una clase sellada puede tener subclases, pero todas las subclases deben estar anidadas dentro de la clase sellada.
sealed no puede aplicarse a interface ni a abstract class (emitirá un warning, pero no causará un error de compilación)
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
}
La principal ventaja de usar clases selladas es que, al usar una expresión `when`, si se puede verificar que la declaración cubre todos los casos, no es necesario añadir una cláusula `else` para dicha declaración.
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` 子句,因为我们已经覆盖了所有的情况
}
Otras extensiones