Kotlin面向对象 (2)✔️扩展

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) {
    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) {
    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) {
    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) {
    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()
}

你可能感兴趣的:(Kotlin面向对象 (2)✔️扩展)