Menu
Coddy logo textTech

Constantes con const

Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 14 de 57.

const val declara una constante en tiempo de compilación: un valor que queda fijado cuando se compila el programa. Se permite en el nivel superior de un archivo y dentro de un object o companion object, y solo para tipos básicos como Int, Double y Boolean, y para String:

const val MAX_PLAYERS = 4

class Lobby {
    val players = mutableListOf<String>()

    fun canStart() = players.size in MIN_PLAYERS..MAX_PLAYERS

    companion object {
        const val MIN_PLAYERS = 2
    }
}

Dentro de main:

val lobby = Lobby()
lobby.players += listOf("ada", "bo")
println(lobby.canStart())
println("${Lobby.MIN_PLAYERS}-$MAX_PLAYERS players")

Salida:

true
2-4 players

Las constantes se nombran en UPPER_SNAKE_CASE. const es más estricto que val: el valor debe conocerse sin ejecutar ningún código, por lo que no se permite una llamada a una función ni una lista. Un val dentro de un objeto también se comparte y es de solo lectura, y acepta cualquier valor:

const val GREETING = "Hello"                  // un literal String
const val TIMEOUT_MS = 30 * 1000              // calculado a partir de literales
// const val START = System.nanoTime()        // error: no es una constante
// const val DAYS = listOf("Mon", "Tue")      // error: solo tipos básicos y String
object Defaults {
    val DAYS = listOf("Mon", "Tue")           // un val compartido de solo lectura
}

Un objeto complementario también puede contener estado mutable compartido. Cada instancia lee y cambia la misma propiedad, lo que resulta adecuado para contadores y cachés. Esta clase mantiene una instancia por nombre, por lo que preguntar dos veces devuelve el mismo objeto (=== comprueba que dos referencias apuntan a un solo objeto):

class Tile private constructor(val name: String) {
    companion object {
        private val cache = mutableMapOf<String, Tile>()
        val created: Int
            get() = cache.size

        fun of(name: String) = cache.getOrPut(name) { Tile(name) }
    }
}

Dentro de main:

val a = Tile.of("grass")
val b = Tile.of("grass")
Tile.of("water")
println(a === b)
println(Tile.created)

Salida:

true
2

¿De nivel superior o complementaria? Una constante o función de nivel superior pertenece a su archivo y se usa por su nombre simple en todos los archivos del paquete. Coloca una constante en un objeto companion cuando pertenece a una sola clase: quienes llaman escriben Lobby.MIN_PLAYERS, lo que indica de dónde proviene el valor, y una private const val permanece dentro de esa clase.

// Limits.kt
const val MAX_UPLOAD_MB = 25                 // usado en todas partes como MAX_UPLOAD_MB

// Lobby.kt
class Lobby {
    companion object {
        const val MIN_PLAYERS = 2            // usado como Lobby.MIN_PLAYERS
        private const val ROOM_PREFIX = "L-" // solo dentro de Lobby
    }
}
challenge icon

Desafío

Fácil

Completa la clase Order(val item: String, val qty: Int). Su objeto companion contiene las constantes MAX_QTY = 10 y PREFIX = "ORD", un contador privado para el siguiente número de pedido, el total compartido de solo lectura totalItems y el count calculado de los pedidos creados. El bloque init requiere una cantidad entre 1 y MAX_QTY con el mensaje quantity must be 1-10 (construido a partir de la constante), después asigna al pedido su id ORD-001, ORD-002, ... y añade su cantidad a totalItems. label() devuelve ORD-001 tea x2.

El código proporcionado imprime max per order: 10, después lee las líneas tea 2 e imprime la etiqueta o el mensaje de error, y finalmente orders: 2, items: 5. Los pedidos rechazados no consumen un número.

Tu código va en Order.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 como está
    val input = generateSequence(::readLine).toList()
    println("max per order: ${Order.MAX_QTY}")
    for (line in input) {
        val (item, qty) = line.split(" ")
        try {
            println(Order(item, qty.toInt()).label())
        } catch (e: IllegalArgumentException) {
            println(e.message)
        }
    }
    println("orders: ${Order.count}, items: ${Order.totalItems}")
}
quiz iconPonte a prueba

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

Practica por tu cuenta: Playground de Kotlin