在kotlin中可以使用一种扩展机制,在原始类型的基础上添加新功能。扩展是一种“轻量级”的继承机制,即使原始类型被限制继承,仍然可以通过扩展机制增强原始类型的功能。kotlin中可以扩展原始类型的函数和属性,原始类型称为“接收类型”。扩展必须针对某种接收类型,所以顶层函数和属性没有扩展。
提示:对于扩展这种“轻量级”机制,很多Java程序员在使用kotlin语言时不擅长使用扩展机制,而是保守地使用继承机制。在设计基于kotlin语言的程序时,要优先考虑扩展机制是否能够满足需求,如果不能再考虑继承机制。
一、扩展函数
fun 接收类型.函数名(参数列表): 返回值类型{
// 函数体
return 返回值
}
可见扩展函数与普通函数相比,只是在函数名前增加一个“接收类型.”。
class User {
var no = 0
var name = ""
}
fun User.printUser() {
println("no=${this.no} name=${this.name}")
}
fun main(args: Array<String>) {
val user = User()
user.no = 30
user.name = "小三"
user.printUser()
}
二、扩展属性
var|val 接收类型.属性名[: 数据类型]
[getter访问器]
[setter访问器]
可见扩展属性与普通属性在声明时的区别是在属性名前面加上“接收类型.”。接收类型可以是任何kotlin数据类型,包括基本数据类型和引用类型。
注意:kotlin 扩展属性没有支持字段 (backing field),所以扩展属性不能初始化,不能使用 field 属性。
class User {
var no = 0
var name = ""
}
var User.des: String
get() = "no=${this.no} name=${this.name}"
set(value) {
println(value)
// println(field) // 编译错误
}
val Int.errorMessage: String
get() = when(this) {
-1 -> "没有登录"
-2 -> "网络异常"
-3 -> "接口异常"
else -> ""
}
fun main(args: Array<String>) {
val user = User()
user.no = 30
user.name = "小三"
user.des // no=30 name=小三
println((-1).errorMessage) // 没有登录
}
三、“成员优先” 原则
无论是扩展属性还是扩展函数,如果接受类型成员中已经有相同的属性和函数,那么在调用属性和函数时,始终是调用接收类型的成员属性和函数。这就是“成员优先” 原则。
class User {
var no = 0
var name = ""
val des by lazy { "成员属性: no=$no, name=$name" }
fun des() = println("成员方法: no=$no, name=$name")
}
val User.des: String
get() = "扩展属性: no=$no, name=$name"
fun User.des() = println("扩展方法: no=$no, name=$name")
fun User.des(who: String) = println("${who}的扩展方法: no=$no, name=$name")
fun main(args: Array<String>) {
val user = User()
user.no = 30
user.name = "小三"
println(user.des) // 成员属性: no=30, name=小三
user.des() // 成员方法: no=30, name=小三
user.des("小咪") // 小咪的扩展方法: no=30, name=小三
}
四、定义中缀运算符
中缀运算符本质上是一个函数。定义中缀运算符,就是要声明一个
infix
关键字修饰的函数,该函数 只能有一个参数,该函数不能是顶层函数,只能是成员函数或扩展函数。
class User {
var no = 0
var name = ""
infix fun score(score: Int) = when(score) { // 1️⃣
in 90..100 -> "优先"
in 80 until 90 -> "良好" // 2️⃣
in 60.until(80) -> "及格" // 3️⃣
in 0 until 60 -> "不及格"
else -> "异常分数"
}
}
infix fun User.toInfo(score: Int): String { // 4️⃣
return "信息: no:$no,name:$name,分数:${this score score}" // 5️⃣
}
fun main(args: Array<String>) {
val user = User()
user.no = 30
user.name = "小三"
println(user score 79) // 及格
println(user toInfo 99) // 信息: no:30,name:小三,分数:优先
}
讲解:代码中第1️⃣行声明一个 成员函数 类型的中缀函数;代码中第4️⃣行声明一个 扩展函数 类型的中缀函数,其中代码第5️⃣行中,调用了成员函数类型的中缀函数。
注意:中缀函数有两种调用方式:
类实例.中缀运算符名称(参数)
如上面代码第3️⃣行类实例 中缀运算符名称 参数
(推荐使用方式)
如上面代码第2️⃣行,是 Int 类型的一个 扩展类型 中缀运算符
中缀函数until的实现
public infix fun Int.until(to: Int): IntRange {
if (to <= Int.MIN_VALUE) return IntRange.EMPTY
return this .. (to - 1).toInt()
}
网友评论