Константы с const
Часть раздела Объектно-ориентированное программирование путешествия по Kotlin на Coddy. Урок 14 из 57.
const val объявляет константу времени компиляции: значение, фиксированное во время компиляции программы. Она допускается на верхнем уровне файла и внутри object или companion object, и только для базовых типов, таких как Int, Double и Boolean, а также для 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
}
}Внутри main:
val lobby = Lobby()
lobby.players += listOf("ada", "bo")
println(lobby.canStart())
println("${Lobby.MIN_PLAYERS}-$MAX_PLAYERS players")Результат:
true
2-4 playersКонстанты именуются в формате UPPER_SNAKE_CASE. const строже, чем val: значение должно быть известно без выполнения какого-либо кода, поэтому вызов функции или список недопустимы. val в объекте также является общим и доступным только для чтения и принимает любое значение:
const val GREETING = "Hello" // строковый литерал
const val TIMEOUT_MS = 30 * 1000 // вычислено из литералов
// const val START = System.nanoTime() // ошибка: не константа
// const val DAYS = listOf("Mon", "Tue") // ошибка: только базовые типы и String
object Defaults {
val DAYS = listOf("Mon", "Tue") // общий val только для чтения
}Объект-компаньон также может хранить общее изменяемое состояние. Каждый экземпляр читает одно и то же свойство и изменяет его, что подходит для счётчиков и кэшей. Этот класс хранит по одному экземпляру для каждого имени, поэтому повторный запрос возвращает тот же объект (=== проверяет, что две ссылки указывают на один объект):
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) }
}
}Внутри main:
val a = Tile.of("grass")
val b = Tile.of("grass")
Tile.of("water")
println(a === b)
println(Tile.created)Вывод:
true
2Верхнего уровня или в объекте-компаньоне? Константа или функция верхнего уровня принадлежит своему файлу и используется по своему простому имени в каждом файле пакета. Поместите константу в объект-компаньон, если она относится к одному классу: вызывающий код пишет Lobby.MIN_PLAYERS, что показывает, откуда происходит значение, а private const val остаётся внутри этого класса.
// Limits.kt
const val MAX_UPLOAD_MB = 25 // используется везде как MAX_UPLOAD_MB
// Lobby.kt
class Lobby {
companion object {
const val MIN_PLAYERS = 2 // используется как Lobby.MIN_PLAYERS
private const val ROOM_PREFIX = "L-" // только внутри Lobby
}
}Задание
ЛегкоЗавершите класс Order(val item: String, val qty: Int). Его сопутствующий объект содержит константы MAX_QTY = 10 и PREFIX = "ORD", приватный счётчик для следующего номера заказа, общее доступное только для чтения значение totalItems и вычисляемое количество созданных заказов count. Блок init требует, чтобы количество находилось между 1 и MAX_QTY, с сообщением quantity must be 1-10 (сформированным на основе константы), затем присваивает заказу идентификатор ORD-001, ORD-002, ... и добавляет его количество к totalItems. label() возвращает ORD-001 tea x2.
Предоставленный код выводит max per order: 10, затем считывает строки tea 2 и выводит метку или сообщение об ошибке, а в конце — orders: 2, items: 5. Отклонённые заказы не занимают номер.
Ваш код должен находиться в Order.kt. В Main.kt содержится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
fun main() {
// Предоставленный код ввода/вывода: оставьте его как есть
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}")
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПервичные конструкторыБлоки init и валидацияВторичные конструкторыПовторение — читательский билет4Наследование
Открытые классы и подклассыПереопределение членовsuper и конструкторыАбстрактные классыПовторение — каталог сотрудников7Специальные классы
Классы данныхКлассы перечисленийЗапечатанные иерархииequals, hashCode, toStringПовторение — трекер заказов10Паттерны проектирования. Часть 2
Делегирование с помощью byПаттерн декораторПаттерн строительПаттерн состояние2Свойства и инкапсуляция
Пользовательские аксессорыМодификаторы видимостиПриватные сеттерыlazy и lateinitПовторение — банковский счёт5Интерфейсы
Объявление интерфейсовМетоды по умолчаниюМножественные интерфейсыИнтерфейсы как типыПовторение — способы оплаты8Обобщения
Обобщённые функцииОбобщённые классыОграничения типовВариативность с in и outПовторение — очередь с приоритетом11Проект: Управление библиотекой
Книги и читателиВыдача книг3Объекты и компаньоны
Объявления объектовОбъекты-компаньоныКонстанты с constОбъектные выраженияПовторение — билетная касса6Полиморфизм
Динамическая диспетчеризацияПроверка типов и умные приведения типовwhen с типамиФункции-расширенияПовторение — смотритель зоопарка9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Песочница Kotlin