Menu
Coddy logo textTech

Stałe z const

Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 14 z 57.

const val deklaruje stałą kompilacyjną: wartość, która jest ustalana podczas kompilowania programu. Można jej używać na najwyższym poziomie pliku oraz wewnątrz object lub companion object, i tylko dla podstawowych typów, takich jak Int, Double i Boolean, oraz dla 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
    }
}

Wewnątrz main:

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

Wynik:

true
2-4 players

Stałe zapisuje się za pomocą NAZW_Z_WIELKICH_LITER_ODDZIELONYCH_PODKREŚLENIAMI. const ma bardziej rygorystyczne wymagania niż val: wartość musi być znana bez uruchamiania jakiegokolwiek kodu, więc wywołanie funkcji ani lista nie są dozwolone. val w obiekcie również jest współdzielone i tylko do odczytu oraz może przyjmować dowolną wartość:

const val GREETING = "Hello"                  // literał typu String
const val TIMEOUT_MS = 30 * 1000              // obliczone na podstawie literałów
// const val START = System.nanoTime()        // błąd: nie jest stałą
// const val DAYS = listOf("Mon", "Tue")      // błąd: dozwolone są tylko typy podstawowe i String
object Defaults {
    val DAYS = listOf("Mon", "Tue")           // współdzielona wartość val tylko do odczytu
}

Obiekt towarzyszący może też przechowywać wspólny, modyfikowalny stan. Każda instancja odczytuje i zmienia tę samą właściwość, co sprawdza się w przypadku liczników i pamięci podręcznych. Ta klasa przechowuje jedną instancję dla każdej nazwy, więc dwukrotne wywołanie zwraca ten sam obiekt (=== sprawdza, czy dwa odwołania wskazują na jeden obiekt):

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

Wewnątrz main:

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

Wynik:

true
2

Na najwyższym poziomie czy w obiekcie towarzyszącym? Stała lub funkcja zdefiniowana na najwyższym poziomie należy do swojego pliku i jest używana pod swoją prostą nazwą w każdym pliku pakietu. Umieść stałą w obiekcie towarzyszącym, gdy należy do jednej klasy: wywołujący zapisują Lobby.MIN_PLAYERS, co wskazuje, skąd pochodzi wartość, a private const val pozostaje wewnątrz tej klasy.

// Limits.kt
const val MAX_UPLOAD_MB = 25                 // używane wszędzie jako MAX_UPLOAD_MB

// Lobby.kt
class Lobby {
    companion object {
        const val MIN_PLAYERS = 2            // używane jako Lobby.MIN_PLAYERS
        private const val ROOM_PREFIX = "L-" // tylko wewnątrz Lobby
    }
}
challenge icon

Wyzwanie

Łatwy

Uzupełnij klasę Order(val item: String, val qty: Int). Jej obiekt towarzyszący przechowuje stałe MAX_QTY = 10 i PREFIX = "ORD", prywatny licznik następnego numeru zamówienia, współdzieloną tylko do odczytu sumę totalItems oraz obliczaną wartość count określającą liczbę utworzonych zamówień. Blok init wymaga, aby ilość mieściła się w zakresie od 1 do MAX_QTY, i używa komunikatu quantity must be 1-10 (utworzonego na podstawie stałej), następnie nadaje zamówieniu identyfikator ORD-001, ORD-002, ... i dodaje jego ilość do totalItems. label() zwraca ORD-001 tea x2.

Dostarczony kod wyświetla max per order: 10, następnie odczytuje wiersze tea 2 i wyświetla etykietę lub komunikat o błędzie, a na końcu orders: 2, items: 5. Odrzucone zamówienia nie zużywają numeru.

Twój kod umieść w pliku Order.kt. Plik Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

fun main() {
    // Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
    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 iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Edytor online Kotlin