lazy y lateinit
Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 10 de 57.
by lazy { ... } retrasa el cálculo de un val hasta que se lee por primera vez y después recuerda el resultado. Es adecuado para valores cuyo cálculo es costoso o que no siempre se necesitan:
class Report(val rows: List<Int>) {
val summary: String by lazy {
println("computing summary")
"total ${rows.sum()}"
}
}Dentro de main:
val r = Report(listOf(3, 4))
println("created")
println(r.summary)
println(r.summary)Salida:
created
computing summary
total 7
total 7El bloque se ejecuta una vez: la segunda lectura anterior utilizó el resultado almacenado. A diferencia de un getter personalizado, que se ejecuta en cada lectura, lazy calcula una vez y almacena en caché:
class Demo {
var reads = 0
val viaGetter: Int
get() { reads++; return 42 }
val viaLazy: Int by lazy { reads++; 42 }
}Dentro de main:
val d = Demo()
repeat(3) { d.viaGetter; d.viaLazy }
println(d.reads)Salida:
4lateinit var declara una propiedad no nula que se asigna más tarde, después de la construcción, por ejemplo mediante un método de configuración. Leerla antes de que se haya asignado provoca una excepción, y ::name.isInitialized lo comprueba:
class Screen {
lateinit var title: String
fun load(t: String) { title = t }
fun ready() = ::title.isInitialized
}Dentro de main:
val s = Screen()
println(s.ready())
s.load("Home")
println(s.ready())
println(s.title)Salida:
false
true
HomePrefiere la inicialización simple cuando el valor se conoce en el momento de la construcción. Usa lazy para un val costoso que puede no ser necesario, y lateinit únicamente para un var cuyo valor realmente llega más tarde; lateinit no funciona con Int, Boolean ni otros tipos primitivos.
val config by lazy { loadConfig() } // calculado en el primer uso, una sola vez
lateinit var user: User // asignado después de la construcción
// lateinit var count: Int // error: no permitido en tipos primitivosDesafío
FácilCompleta la clase Document(val text: String). Añade wordCount como una propiedad lazy que cuente las palabras (separadas por espacios simples) y registre cada cálculo sumando 1 a computations, y un lateinit var author: String con un método credit() que devuelva by Ada o by unknown cuando no se haya establecido el autor.
El código proporcionado lee el texto, lee wordCount tres veces, establece el autor cuando hay una segunda línea e imprime words 5, computed 1, by Ada.
Tu código va en Document.kt. Main.kt contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
fun main() {
// Código de entrada/salida suministrado: déjalo tal como está
val input = generateSequence(::readLine).toList()
val doc = Document(input[0])
val reads = List(3) { doc.wordCount }
val words = reads.first()
if (input.size > 1) doc.author = input[1]
println("words $words, computed ${doc.computations}, ${doc.credit()}")
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesConstructores primariosBloques init y validaciónConstructores secundariosRepaso - Tarjeta de biblioteca4Herencia
Clases abiertas y subclasesSobrescritura de miembrossuper y constructoresClases abstractasRepaso: directorio del personal2Propiedades y encapsulación
Accesores personalizadosModificadores de visibilidadSetters privadoslazy y lateinitRepaso: cuenta bancaria5Interfaces
Declaración de interfacesMétodos predeterminadosInterfaces múltiplesInterfaces como tiposRepaso: métodos de pago8Genéricos
Funciones genéricasClases genéricasRestricciones de tiposVariancia con in y outRepaso - Cola de prioridad11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Playground de Kotlin