Hàm mở rộng
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 30 trên 57.
Hàm mở rộng thêm một hàm vào kiểu dữ liệu đã có mà không cần thay đổi mã nguồn của kiểu đó. Tên hàm được viết sau kiểu nhận, bên trong hàm, this tham chiếu đến kiểu nhận và bạn cũng có thể lược bỏ từ khóa này:
fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0Bên trong main:
println("hello".shout())
println(7.isEven())
println(listOf(1, 2, 3, 4).count { it.isEven() })Đầu ra:
HELLO!
false
2Extension cũng hoạt động với các lớp của bạn, và thuộc tính mở rộng bổ sung các thuộc tính được tính toán. Extension không thể bổ sung trạng thái được lưu trữ và chỉ truy cập được các thành viên public của đối tượng nhận:
class Temperature(val celsius: Double)
val Temperature.fahrenheit: Double
get() = celsius * 9 / 5 + 32
fun Temperature.describe() = "$celsius C is $fahrenheit F"Bên trong main:
println(Temperature(100.0).describe())Đầu ra:
100.0 C is 212.0 FCác phần mở rộng được phân giải theo cách tĩnh: kiểu được khai báo của biểu thức quyết định phần mở rộng nào được chọn khi chương trình biên dịch, chứ không phải lớp của đối tượng. Đây là điểm khác biệt chính so với thành viên được ghi đè:
open class Shape {
open fun member() = "shape member"
}
class Circle : Shape() {
override fun member() = "circle member"
}
fun Shape.ext() = "shape extension"
fun Circle.ext() = "circle extension"Bên trong main:
val s: Shape = Circle()
println(s.member())
println(s.ext())Đầu ra:
circle member
shape extensionKhi lớp đã có một thành viên cùng chữ ký, thành viên đó luôn được ưu tiên. Hãy dùng thành viên cho hành vi thuộc về kiểu và có thể được ghi đè; dùng hàm mở rộng cho các tiện ích được thêm từ bên ngoài, chẳng hạn như định dạng cho một lớp mà bạn không sở hữu:
class Robot {
fun greet() = "member greet"
}
fun Robot.greet() = "extension greet"
fun Robot.wave() = "extension wave"Bên trong main:
val r = Robot()
println(r.greet())
println(r.wave())Đầu ra:
member greet
extension waveThử thách
DễMoney(cents) đã có sẵn trong Money.kt. Hãy viết các phần mở rộng cho nó trong MoneyExtensions.kt: các thuộc tính mở rộng Int.dollars và Int.cents, chuyển một số thành Money (12.dollars là 1200 xu), Money.format(), trả về $12.50 (hoặc -$3.05 với số tiền âm), List<Money>.total(), trả về tổng dưới dạng Money, và Money.split(parts), chia thành parts khoản tiền chênh nhau tối đa một xu, với các khoản lớn hơn đứng trước.
Code được cung cấp đọc các dòng 12 dollars hoặc 50 cents và dòng cuối cùng có số phần. Code in ra từng khoản tiền, total: $12.50 và split 3: $4.17 $4.17 $4.16.
Code của bạn nằm trong MoneyExtensions.kt và Money.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()
val amounts = input.dropLast(1).map { line ->
val (n, unit) = line.split(" ")
if (unit == "dollars") n.toInt().dollars else n.toInt().cents
}
for (m in amounts) println(m.format())
val total = amounts.total()
println("total: ${total.format()}")
val parts = input.last().toInt()
println("split $parts: " + total.split(parts).joinToString(" ") { it.format() })
}
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