函数扩展和属性扩展 3个月前

Kotlin 支持 扩展函数 和 扩展属性。其能够扩展一个类的新功能而无需继承该类或使用像装饰者这样的设计模式等。

大多数时候我们在顶层定义扩展,即直接在包里:

package com.easy.kotlin

val <T> List<T>.lastIndex: Int get() = size - 1

fun String.notEmpty(): Boolean {
    return !this.isEmpty()
}

这样我们就可以在整个包里使用这些扩展。

要使用其他包的扩展,我们需要在调用方导入它:

package com.example.usage

import foo.bar.goo // 导入所有名为“goo”的扩展
                   // 或者
import foo.bar.*   // 从“foo.bar”导入一切

fun usage(baz: Baz) {
    baz.goo()
}

扩展函数

声明一个扩展函数,我们需要用_被扩展的类型_来作为前缀。

比如说,我们不喜欢类似下面的_双重否定_式的逻辑判断(绕脑子):

>>> !"123".isEmpty()
true

我们就可以为String类型扩展一个notEmpty()函数:

>>> fun String.notEmpty():Boolean{
... return !this.isEmpty()
... }

>>> "".notEmpty()
false

>>> "123".notEmpty()
true

下面代码为 MutableList<Int> 添加一个swap 函数:

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // this对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

这个 this 关键字在扩展函数内部对应到接收者对象(传过来的在点.符号前的对象) 现在,我们对任意 MutableList<Int> 调用该函数了。

当然,这个函数对任何 MutableList<T> 起作用,我们可以泛化它:

fun <T> MutableList<T>.mswap(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

为了在接收者类型表达式中使用泛型,我们要在函数名前声明泛型参数。

完整代码示例

package com.easy.kotlin

val <T> List<T>.lastIndex: Int get() = size - 1

fun String.notEmpty(): Boolean {
    return !this.isEmpty()
}

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // this对应该列表m
    this[index1] = this[index2]
    this[index2] = tmp
}

fun <T> MutableList<T>.mswap(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

class ExtensionsDemo {

    fun useExtensions() {
        val a = "abc"
        println(a.notEmpty())//true

        val mList = mutableListOf<Int>(1, 2, 3, 4, 5)
        println("Before Swap:")
        println(mList)//[1, 2, 3, 4, 5]
        mList.swap(0, mList.size - 1)
        println("After Swap:")
        println(mList)//[5, 2, 3, 4, 1]

        val mmList = mutableListOf<String>("a12", "b34", "c56", "d78")
        println("Before Swap:")
        println(mmList)//[a12, b34, c56, d78]
        mmList.mswap(1, 2)
        println("After Swap:")
        println(mmList)//[a12, c56, b34, d78]

        val mmmList = mutableListOf<Int>(100, 200, 300, 400, 500)
        println("Before Swap:")
        println(mmmList)
        mmmList.mswap(0, mmmList.lastIndex)
        println("After Swap:")
        println(mmmList)
    }

    class Inner {
        fun useExtensions() {
            val mmmList = mutableListOf<Int>(100, 200, 300, 400, 500)
            println(mmmList.lastIndex)
        }
    }
}

测试代码

package com.easy.kotlin

import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@RunWith(JUnit4::class)
class ExtensionsDemoTest {
    @Test fun testExtensionsDemo() {
        val demo = ExtensionsDemo()
        demo.useExtensions()
    }
}

扩展不是真正的修改他们所扩展的类。我们定义一个扩展,其实并没有在一个类中插入新函数,仅仅是通过该类型的变量,用点.表达式去调用这个新函数。

扩展属性

和函数类似,Kotlin 支持扩展属性:

val <T> List<T>.lastIndex: Int
    get() = size - 1

注意:由于扩展没有实际的将成员插入类中,因此对扩展的属性来说,它的行为只能由显式提供的 getters/setters 定义。

代码示例:

package com.easy.kotlin

val <T> List<T>.lastIndex: Int get() = size - 1

我们可以直接使用包com.easy.kotlin中扩展的属性lastIndex :

image

image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2223305
累计阅读

热门教程文档

React
18小节
C++
73小节
Linux
51小节
10.x
88小节
MySQL
34小节