Hằng số với const
Thuộc phần Lập trình hướng đối tượng trong hành trình Kotlin của Coddy. Bài học 14 trên 57.
const val khai báo một hằng số tại thời điểm biên dịch: giá trị cố định khi chương trình được biên dịch. Bạn có thể khai báo hằng số này ở cấp cao nhất của tệp và bên trong object hoặc companion object, chỉ áp dụng cho các kiểu cơ bản như Int, Double và Boolean, cũng như 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
}
}Bên trong main:
val lobby = Lobby()
lobby.players += listOf("ada", "bo")
println(lobby.canStart())
println("${Lobby.MIN_PLAYERS}-$MAX_PLAYERS players")Đầu ra:
true
2-4 playersHằng số được đặt tên theo dạng UPPER_SNAKE_CASE. const có quy tắc nghiêm ngặt hơn val: giá trị phải xác định được mà không cần chạy code, vì vậy không thể dùng lời gọi hàm hoặc danh sách. val trong một đối tượng cũng được chia sẻ và chỉ đọc, đồng thời chấp nhận mọi giá trị:
const val GREETING = "Hello" // một giá trị chuỗi String viết trực tiếp
const val TIMEOUT_MS = 30 * 1000 // tính từ các giá trị viết trực tiếp
// const val START = System.nanoTime() // lỗi: không phải hằng số
// const val DAYS = listOf("Mon", "Tue") // lỗi: chỉ chấp nhận các kiểu dữ liệu cơ bản và String
object Defaults {
val DAYS = listOf("Mon", "Tue") // một val chỉ đọc dùng chung
}Đối tượng companion cũng có thể lưu giữ trạng thái có thể thay đổi dùng chung. Mỗi instance đọc và thay đổi cùng một thuộc tính, rất phù hợp với bộ đếm và bộ nhớ đệm. Lớp này giữ một instance cho mỗi tên, vì vậy gọi hai lần sẽ trả về cùng một đối tượng (=== kiểm tra xem hai tham chiếu có trỏ đến cùng một đối tượng hay không):
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) }
}
}Bên trong main:
val a = Tile.of("grass")
val b = Tile.of("grass")
Tile.of("water")
println(a === b)
println(Tile.created)Đầu ra:
true
2Cấp cao nhất hay companion? Một hằng số hoặc hàm cấp cao nhất thuộc về tệp của nó và được dùng bằng tên thuần trong mọi tệp của gói. Đặt một hằng số trong companion khi nó thuộc về một lớp: nơi gọi viết Lobby.MIN_PLAYERS, cho biết giá trị này đến từ đâu, còn private const val chỉ nằm trong lớp đó.
// Limits.kt
const val MAX_UPLOAD_MB = 25 // dùng ở mọi nơi dưới tên MAX_UPLOAD_MB
// Lobby.kt
class Lobby {
companion object {
const val MIN_PLAYERS = 2 // dùng dưới tên Lobby.MIN_PLAYERS
private const val ROOM_PREFIX = "L-" // chỉ dùng trong Lobby
}
}Thử thách
DễHoàn thiện lớp (class) Order(val item: String, val qty: Int). Đối tượng companion của lớp chứa các hằng số MAX_QTY = 10 và PREFIX = "ORD", một bộ đếm riêng cho số đơn hàng tiếp theo, tổng dùng chung chỉ đọc totalItems và count tính toán số đơn hàng đã tạo. Khối init yêu cầu số lượng nằm trong khoảng từ 1 đến MAX_QTY, kèm thông báo quantity must be 1-10 (được tạo từ hằng số), sau đó gán mã định danh cho đơn hàng lần lượt là ORD-001, ORD-002, ... và cộng số lượng của đơn hàng vào totalItems. label() trả về ORD-001 tea x2.
Code được cung cấp in ra max per order: 10, sau đó đọc các dòng tea 2 và in nhãn hoặc thông báo lỗi, cuối cùng in ra orders: 2, items: 5. Đơn hàng bị từ chối không làm mất số thứ tự.
Viết code của bạn trong Order.kt. Main.kt chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
fun main() {
// Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
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}")
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpHàm khởi tạo chínhKhối init và kiểm tra tính hợp lệHàm khởi tạo phụÔn tập: thẻ thư viện4Kế thừa
Lớp mở và lớp conGhi đè thành viênsuper và hàm khởi tạoLớp trừu tượngÔn tập: Danh bạ nhân viên2Thuộc tính và tính đóng gói
Trình truy cập tùy chỉnhBộ sửa đổi phạm vi truy cậpSetter riêng tưlazy và lateinitÔn tập: tài khoản ngân hàng5Giao diện
Khai báo giao diệnPhương thức mặc địnhNhiều giao diệnGiao diện như kiểu dữ liệuÔn tập: Phương thức thanh toán3Đối tượng và đối tượng đồng hành
Khai báo đối tượngĐối tượng đồng hànhHằng số với constBiểu thức đối tượngÔn tập: Phòng bán véTự luyện tập: Playground Kotlin