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

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

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

    1. import foo.bar.goo // 导入所有名为“goo”的扩展
    2. // 或者
    3. import foo.bar.* // 从“foo.bar”导入一切
    4. fun usage(baz: Baz) {
    5. baz.goo()
    6. }

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

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

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

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

    1. val tmp = this[index1] // this对应该列表
    2. this[index1] = this[index2]
    3. this[index2] = tmp
    4. }

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

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

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

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

    完整代码示例

    1. package com.easy.kotlin
    2. import org.junit.runner.RunWith
    3. import org.junit.runners.JUnit4
    4. @RunWith(JUnit4::class)
    5. class ExtensionsDemoTest {
    6. @Test fun testExtensionsDemo() {
    7. val demo = ExtensionsDemo()
    8. demo.useExtensions()
    9. }
    10. }

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

    扩展属性

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

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

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

    代码示例:

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