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 内でのみ
}
}チャレンジ
簡単クラス 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}")
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Kotlinプレイグラウンド