【Kotlin】扩展属性、扩展函数

1 类的扩展

Kotlin 提供了扩展类或接口的操作,而无需通过类继承或使用装饰器等设计模式,来为某个类添加一些额外的函数或是属性,我们只需要通过一个被称为扩展的特殊声明来完成。通过这种机制,我们可以将那些第三方类不具备的功能强行进行扩展,来方便我们的操作。

1.1 扩展内置类

1.1.1 扩展属性

Kotlin 复制代码
fun main() {
    var str = "abc"
    str.property = 5 // 打印: set property, value=5
    var property = str.property // 打印: get property
    println(property) // 打印: 10
}

var String.property: Int
    set(value) {
        println("set property, value=$value")
    }
    get() {
        println("get property")
        return 10
    }

说明:扩展属性并不是真的往类中添加属性,也不会真的插入一个成员字段到类的定义中,导致没有变量存储我们的数据,我们只能明确定义一个 getter 和 setter 来创建扩展属性,才能让它使用起来真的像是类的属性一样。

如下,如果没有定义 getter 和 setter方法,将会报错如下。

1.1.2 扩展函数

Kotlin 复制代码
fun main() {
    var str = "abc"
    str.myFun("xxx") // 打印: myFun, this=abc, value=xxx
}

fun String.myFun(value: String) {
    println("myFun, this=$this, value=$value")
}

1.2 扩展自定义类

1.2.1 扩展属性

1)扩展新属性

Kotlin 复制代码
fun main() {
    var stu = Student()
    stu.name = "Mary" // 打印: set name, value=Mary
    var name = stu.name // 打印: get name
    println(name) // 打印: Tom
}

class Student

var Student.name: String
    set(value) {
        println("set name, value=$value")
    }
    get() {
        println("get name")
        return "Tom"
    }

2)扩展旧属性

Kotlin 复制代码
fun main() {
    var stu = Student("Jack")
    stu.name = "Mary" // 无打印
    var name = stu.name // 无打印
    println(name) // 打印: Mary
}

class Student(var name: String)

var Student.name: String // 扩展属性不会生效
    set(value) {
        println("set name, value=$value")
    }
    get() {
        println("get name")
        return "Tom"
    }

说明:如果扩展类中的同名同类型属性,扩展将不会生效。

1.2.2 扩展函数

1)扩展新函数

Kotlin 复制代码
fun main() {
    var stu = Student("Mary")
    stu.test() // 打印: test, name=Mary
}

class Student(var name: String)

fun Student.test() {
    println("test, name=$name")
}

2)扩展旧函数

Kotlin 复制代码
fun main() {
    var stu = Student("Mary")
    stu.test() // 打印: inner, name=Mary
}

class Student(var name: String) {
    fun test() {
        println("inner, name=$name")
    }
}

fun Student.test() { // 扩展函数不会生效
    println("extended, name=$name")
}

说明:如果扩展类中的同名同参函数,扩展将不会生效。

1.3 重写父类的扩展函数

类的扩展是静态的,实际上并不会修改它们原本的类,也不会将新成员插入到类中,仅仅是将我们定义的功能变得可调用,使用起来就像真的有一样。同时,在编译时也会明确具体调用的扩展函数。

1.3.1 扩展属性

Kotlin 复制代码
fun main() {
    var stu: Student = Student()
    var name1 = stu.name // 打印: Student, get name
    println(name1) // 打印: Mary
    var peo: People = stu
    var name2 = peo.name // 打印: People, get name
    println(name2) // 打印: Tom
}

open class People
class Student: People()

var People.name: String
    set(value) {
        println("People, set name, value=$value")
    }
    get() {
        println("People, get name")
        return "Tom"
    }

var Student.name: String
    set(value) {
        println("Student, set name, value=$value")
    }
    get() {
        println("Student, get name")
        return "Mary"
    }

1.3.2 扩展函数

Kotlin 复制代码
fun main() {
    var stu: Student = Student()
    println(stu.type()) // 打印: Student
    var peo: People = stu
    println(peo.type()) // 打印: People
}

open class People
class Student: People()

fun People.type() = "People"
fun Student.type() = "Student"

1.4 匿名扩展函数

匿名函数的使用详见 →【Kotlin】函数

Kotlin 复制代码
fun main() {
    var myFun: String.() -> Int = fun String.(): Int {
        return this.length
    }
    println("abc".myFun()) // 打印: 3
}

可以使用 Lambda 表达式简化如下,Lambda 表达式的使用详见 → 【Kotlin】Lambda表达式

Kotlin 复制代码
fun main() {
    var myFun: String.() -> Int = {
        this.length
    }
    println("abc".myFun()) // 打印: 3
}

1.5 扩展函数作为参数

Kotlin 复制代码
fun main() {
    var len = "abc".len { this.length }
    println(len) // 打印: 3
}

fun String.len(func: String.() -> Int): Int {
    return func()
}

2 官方扩展函数

2.1 源码

Kotlin 提供了一些泛型扩展函数(在 Standard.kt 中),如:apply、also、run、let、takeIf、takeUnless 等,作用是执行 block 函数的内容,并且返回 T 或 block 的返回值,通常用于判空处理。

|-------|--------------|---------|----------|-------|---------|
| 函数 | block是否为扩展函数 | block入参 | block返回值 | 函数返回值 | 访问 T 对象 |
| apply | 是 | 无 | 无 | T | this |
| also | 否 | T | 无 | T | it |
| run | 是 | 无 | R | R | this |
| let | 否 | T | R | R | it |

2.1.1 apply

Kotlin 复制代码
public inline fun <T> T.apply(block: T.() -> Unit): T {
    ...
    block()
    return this
}

2.1.2 also

Kotlin 复制代码
public inline fun <T> T.also(block: (T) -> Unit): T {
    ...
    block(this)
    return this
}

2.1.3 run

Kotlin 复制代码
public inline fun <T, R> T.run(block: T.() -> R): R {
    ...
    return block()
}

2.1.4 let

Kotlin 复制代码
public inline fun <T, R> T.let(block: (T) -> R): R {
    ...
    return block(this)
}

2.1.5 takeIf

Kotlin 复制代码
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    ...
    return if (predicate(this)) this else null
}

2.1.6 takeUnless

Kotlin 复制代码
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    ...
    return if (!predicate(this)) this else null
}

2.1.7 with

Kotlin 复制代码
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    ...
    return receiver.block()
}

说明:with 不是扩展函数,但入参 block 是扩展函数。

2.2 应用

2.2.1 apply 应用

Kotlin 复制代码
fun main() {
    var stu = Student()
    test(stu)
}

fun test(stu: Student?) {
    stu?.apply {
        this.name = "Tom"
        this.age = 23
    }
    println(stu) // 打印: [Tom, 23]
}

class Student {
    var name: String? = null
    var age: Int = 0

    override fun toString(): String {
        return "[$name, $age]"
    }
}

说明:also、run、let 的应用与 apply 类似。

2.2.2 takeIf 应用

Kotlin 复制代码
fun main() {
    var str = "ABC"
    var str2 = str.takeIf { it.length % 2 == 1 }?.let { it + it.reversed().substring(1) }
    println(str2) // 打印: ABCBA
}

2.2.3 with 应用

Kotlin 复制代码
fun main() {
    var str = "ABC"
    var len = with(str) { this.length }
    println(len) // 打印: 3
}
相关推荐
努力的派大星星2 个月前
【JavaScript】深入理解 `let`、`var` 和 `const`
开发语言·前端·javascript·const·let·var
NPE~7 个月前
Bug:Windows 11/10关于扩展属性不一致
windows·bug·win11·扩展属性
'訫乁8 个月前
ES6-let
es6·let
easylee8 个月前
JavaScript apply、call、bind 函数详解
javascript·apply·bind
川峰9 个月前
Kotlin 笔记 -- Kotlin 语言特性的理解(一)
kotlin·函数对象·out和in·扩展函数·object单例·接口委托by·nothing
丁总学Java1 年前
在JS中,var 、let 、const 总结
开发语言·前端·javascript·const·let·var
想想吴1 年前
11 - git stash 开发中临时加塞了紧急任务怎么处理
git·git stash·apply·pop