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 comovalovar ;

  • Las clases de datos no pueden declararse comoabstract, 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