Menu
Coddy logo textTech

Costanti con const

Fa parte della sezione Programmazione orientata agli oggetti del percorso Kotlin di Coddy. Lezione 14 di 57.

const val dichiara una costante in fase di compilazione: un valore che viene fissato quando il programma viene compilato. È consentita al livello superiore di un file e all'interno di un object o di un companion object, e solo per tipi di base come Int, Double e Boolean, e per 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
    }
}

All'interno di main:

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

Output:

true
2-4 players

Le costanti hanno un nome in MAIUSCOLO_CON_UNDERSCORE. const è più restrittivo di val: il valore deve essere noto senza eseguire codice, quindi non sono consentite chiamate a funzioni o liste. Anche un val in un oggetto è condiviso e di sola lettura, e può accettare qualsiasi valore:

const val GREETING = "Hello"                  // un valore letterale String
const val TIMEOUT_MS = 30 * 1000              // calcolato a partire da valori letterali
// const val START = System.nanoTime()        // errore: non è una costante
// const val DAYS = listOf("Mon", "Tue")      // errore: sono ammessi solo i tipi di base e String
object Defaults {
    val DAYS = listOf("Mon", "Tue")           // un val condiviso di sola lettura
}

Un oggetto companion può anche contenere uno stato mutabile condiviso. Ogni istanza legge e modifica la stessa proprietà, il che è adatto a contatori e cache. Questa classe mantiene un’unica istanza per nome, quindi richiedendola due volte restituisce lo stesso oggetto (=== verifica che due riferimenti puntino a un unico oggetto):

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) }
    }
}

All’interno di main:

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

Output:

true
2

Di livello superiore o nel companion? Una costante o una funzione di livello superiore appartiene al suo file e viene usata con il suo nome semplice in ogni file del pacchetto. Inserisci una costante in un companion quando appartiene a una sola classe: chi la richiama scrive Lobby.MIN_PLAYERS, indicando da dove proviene il valore, e un private const val rimane all'interno di quella classe.

// Limits.kt
const val MAX_UPLOAD_MB = 25                 // usato ovunque come MAX_UPLOAD_MB

// Lobby.kt
class Lobby {
    companion object {
        const val MIN_PLAYERS = 2            // usato come Lobby.MIN_PLAYERS
        private const val ROOM_PREFIX = "L-" // solo all'interno di Lobby
    }
}
challenge icon

Sfida

Facile

Completa la classe Order(val item: String, val qty: Int). Il suo oggetto companion contiene le costanti MAX_QTY = 10 e PREFIX = "ORD", un contatore privato per il numero del prossimo ordine, il totale condiviso di sola lettura totalItems e il valore calcolato count degli ordini creati. Il blocco init richiede una quantità compresa tra 1 e MAX_QTY con il messaggio quantity must be 1-10 (generato dalla costante), poi assegna all'ordine il suo id ORD-001, ORD-002, ... e aggiunge la sua quantità a totalItems. label() restituisce ORD-001 tea x2.

Il codice fornito stampa max per order: 10, poi legge le righe tea 2 e stampa l'etichetta o il messaggio di errore, e infine orders: 2, items: 5. Gli ordini rifiutati non consumano un numero.

Il tuo codice va in Order.kt. Main.kt contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

fun main() {
    // Codice di input/output fornito: lascialo così com'è
    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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Playground Kotlin