Menu
Coddy logo textTech

const による定数

CoddyのKotlinジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 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

定数には大文字のスネークケースを使用します。constはvalよりも厳格です。値はコードを実行せずにわかっていなければならないため、関数呼び出しやリストは使用できません。オブジェクト内のvalも共有され、読み取り専用であり、任意の値を受け取れます。

const val GREETING = "Hello"                  // 文字列リテラル
const val TIMEOUT_MS = 30 * 1000              // リテラルから計算される
// const val START = System.nanoTime()        // error: 定数ではない
// const val DAYS = listOf("Mon", "Tue")      // error: 基本型と String のみ
object Defaults {
    val DAYS = listOf("Mon", "Tue")           // 共有の読み取り専用 val
}

コンパニオンオブジェクトは共有される可変状態も保持できます。すべてのインスタンスが同じプロパティを読み取り、変更するため、カウンターやキャッシュに適しています。このクラスは名前ごとに1つのインスタンスを保持するため、2回問い合わせると同じオブジェクトが返されます(===は、2つの参照が1つのオブジェクトを指していることを確認します)。

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

トップレベル、それともコンパニオン? トップレベルの定数または関数はそのファイルに属し、パッケージ内のすべてのファイルで単純な名前を使って呼び出されます。定数が1つのクラスに属する場合は、コンパニオンに置きます。呼び出し側は 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 内でのみ
    }
}
challenge icon

チャレンジ

簡単

クラス 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、... のような id を割り当て、数量を 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}")
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Kotlinプレイグラウンド