Menu
Coddy logo textTech

Konstanten mit const

Teil des Abschnitts Objektorientierte Programmierung der Kotlin-Journey von Coddy. Lektion 14 von 57.

const val deklariert eine Konstanten zur Compile-Zeit: einen Wert, der beim Kompilieren des Programms festgelegt wird. Sie ist auf der obersten Ebene einer Datei und innerhalb eines object oder companion object zulässig und nur für die grundlegenden Typen wie Int, Double und Boolean sowie für 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
    }
}

Innerhalb von main:

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

Ausgabe:

true
2-4 players

Konstanten werden in UPPER_SNAKE_CASE benannt. const ist strenger als val: Der Wert muss bekannt sein, ohne dass Code ausgeführt wird, daher sind ein Funktionsaufruf oder eine Liste nicht erlaubt. Ein val in einem Objekt wird ebenfalls gemeinsam genutzt und ist schreibgeschützt und akzeptiert jeden Wert:

const val GREETING = "Hello"                  // ein String-Literal
const val TIMEOUT_MS = 30 * 1000              // aus Literalen berechnet
// const val START = System.nanoTime()        // Fehler: keine Konstante
// const val DAYS = listOf("Mon", "Tue")      // Fehler: nur Basistypen und String
object Defaults {
    val DAYS = listOf("Mon", "Tue")           // ein gemeinsames schreibgeschütztes val
}

Ein Companion-Objekt kann auch gemeinsam genutzten veränderlichen Zustand enthalten. Jede Instanz liest und ändert dieselbe Eigenschaft, was sich für Zähler und Caches eignet. Diese Klasse verwaltet eine Instanz pro Namen, sodass eine zweimalige Abfrage dasselbe Objekt zurückgibt (=== prüft, ob zwei Referenzen auf ein Objekt zeigen):

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

Innerhalb von main:

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

Ausgabe:

true
2

Top-Level oder Companion? Eine Top-Level-Konstante oder -Funktion gehört zu ihrer Datei und wird in jeder Datei des Pakets unter ihrem einfachen Namen verwendet. Setze eine Konstante in einen Companion, wenn sie zu einer Klasse gehört: Aufrufer schreiben Lobby.MIN_PLAYERS, wodurch ersichtlich wird, woher der Wert stammt, und ein private const val bleibt innerhalb dieser Klasse.

// Limits.kt
const val MAX_UPLOAD_MB = 25                 // überall verwendet als MAX_UPLOAD_MB

// Lobby.kt
class Lobby {
    companion object {
        const val MIN_PLAYERS = 2            // verwendet als Lobby.MIN_PLAYERS
        private const val ROOM_PREFIX = "L-" // nur innerhalb von Lobby
    }
}
challenge icon

Aufgabe

Einfach

Vervollständige die Klasse Order(val item: String, val qty: Int). Ihr Begleitobjekt enthält die Konstanten MAX_QTY = 10 und PREFIX = "ORD", einen privaten Zähler für die nächste Bestellnummer, die schreibgeschützte gemeinsame Summe totalItems und die berechnete Anzahl count der erstellten Bestellungen. Der init-Block verlangt eine Menge zwischen 1 und MAX_QTY mit der Meldung quantity must be 1-10 (aus der Konstante gebildet), weist der Bestellung anschließend ihre ID ORD-001, ORD-002, ... zu und addiert ihre Menge zu totalItems. label() gibt ORD-001 tea x2 zurück.

Der bereitgestellte Code gibt max per order: 10 aus, liest anschließend die Zeile tea 2 ein und gibt das Label oder die Fehlermeldung aus; schließlich gibt er orders: 2, items: 5 aus. Abgelehnte Bestellungen verbrauchen keine Nummer.

Dein Code gehört in Order.kt. Main.kt enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

fun main() {
    // Gelieferter Ein-/Ausgabecode: belasse ihn wie er ist
    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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Kotlin-Playground