Menu
Coddy logo textTech

Constantes com const

Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 14 de 57.

const val declara uma constante em tempo de compilação: um valor fixado quando o programa é compilado. Ela é permitida no nível superior de um arquivo e dentro de um object ou companion object, e somente para tipos básicos como Int, Double e Boolean, e 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")

Saída:

true
2-4 players

As constantes são nomeadas em UPPER_SNAKE_CASE. const é mais restrito que val: o valor deve ser conhecido sem executar nenhum código, portanto uma chamada de função ou uma lista não é permitida. Um val em um objeto também é compartilhado e somente leitura, além de aceitar qualquer valor:

const val GREETING = "Hello"                  // um literal String
const val TIMEOUT_MS = 30 * 1000              // calculado a partir de literais
// const val START = System.nanoTime()        // erro: não é uma constante
// const val DAYS = listOf("Mon", "Tue")      // erro: apenas tipos básicos e String
object Defaults {
    val DAYS = listOf("Mon", "Tue")           // um val compartilhado somente leitura
}

Um objeto companion também pode conter estado mutável compartilhado. Cada instância lê e altera a mesma propriedade, o que é adequado para contadores e caches. Esta classe mantém uma instância por nome, portanto, solicitar duas vezes retorna o mesmo objeto (=== verifica se duas referências apontam para um único 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)

Saída:

true
2

Nível superior ou companion? Uma constante ou função de nível superior pertence ao seu arquivo e é usada pelo seu nome simples em todos os arquivos do pacote. Coloque uma constante em um companion quando ela pertencer a uma classe: os chamadores escrevem Lobby.MIN_PLAYERS, o que indica de onde o valor vem, e um private const val permanece dentro dessa classe.

// Limits.kt
const val MAX_UPLOAD_MB = 25                 // usado em todos os lugares 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-" // apenas dentro de Lobby
    }
}
challenge icon

Desafio

Fácil

Complete a classe Order(val item: String, val qty: Int). Seu objeto companion contém as constantes MAX_QTY = 10 e PREFIX = "ORD", um contador privado para o próximo número do pedido, o total compartilhado somente para leitura totalItems e a count calculada dos pedidos criados. O bloco init exige uma quantidade entre 1 e MAX_QTY com a mensagem quantity must be 1-10 (construída a partir da constante), depois atribui ao pedido seu id ORD-001, ORD-002, ... e adiciona sua quantidade a totalItems. label() retorna ORD-001 tea x2.

O código fornecido imprime max per order: 10, depois lê as linhas tea 2 e imprime o rótulo ou a mensagem de erro e, por fim, orders: 2, items: 5. Pedidos recusados não consomem um número.

Seu código deve ficar em Order.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

fun main() {
    // Código de entrada/saída fornecido: mantenha-o 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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Kotlin