扩展函数
本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 30 课,共 57 课。
扩展函数可以为现有类型添加函数,而无需更改该类型的源代码。它的名称写在接收者类型之后,在函数内部,this 表示接收者,也可以省略:
fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0在 main 内部:
println("hello".shout())
println(7.isEven())
println(listOf(1, 2, 3, 4).count { it.isEven() })输出:
HELLO!
false
2扩展也适用于你自己创建的类,扩展属性可以添加计算属性。扩展无法添加存储状态,并且只能访问接收者的公共成员:
class Temperature(val celsius: Double)
val Temperature.fahrenheit: Double
get() = celsius * 9 / 5 + 32
fun Temperature.describe() = "$celsius C is $fahrenheit F"在 main 中:
println(Temperature(100.0).describe())输出:
100.0 C is 212.0 F扩展是以静态方式解析的:表达式的声明类型决定了在编译程序时使用哪个扩展,而不是对象的类。这是扩展与被重写的成员之间的主要区别:
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"在 main 中:
val s: Shape = Circle()
println(s.member())
println(s.ext())输出:
circle member
shape extension如果类中已经有一个签名相同的成员,那么总是优先使用该成员。对于属于该类型且可能被重写的行为,使用成员;对于从外部添加的辅助功能,例如为你不拥有的类添加格式化功能,则使用扩展:
class Robot {
fun greet() = "member greet"
}
fun Robot.greet() = "extension greet"
fun Robot.wave() = "extension wave"在 main 中:
val r = Robot()
println(r.greet())
println(r.wave())输出:
member greet
extension wave挑战
简单Money(cents) 已在 Money.kt 中提供。请在 MoneyExtensions.kt 中为它编写扩展:扩展属性 Int.dollars 和 Int.cents,用于将数字转换为 Money(12.dollars 是 1200 美分);Money.format(),用于返回 $12.50(负数金额则返回 -$3.05);List<Money>.total(),用于将总和作为 Money 返回;以及 Money.split(parts),用于将金额拆分为 parts 份,各份之间最多相差 1 美分,较大的金额排在前面。
提供的代码会读取若干行 12 dollars 或 50 cents,以及最后一行中的份数。它会输出每笔金额、total: $12.50 和 split 3: $4.17 $4.17 $4.16。
你的代码应写在 MoneyExtensions.kt 和 Money.kt 中。Main.kt 包含提供的输入/输出代码,不能修改。
亲手试试
fun main() {
// 提供的输入和输出代码:保持原样
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() })
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Kotlin 在线编辑器