Kotlin小记-5 扩展

335 阅读3分钟

扩展函数

声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀

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

扩展是静态解析的

扩展不能真正的修改他们所扩展的类。通过定义一个扩展,你并没有在一个类中插入新成员, 仅仅是可以通过该类型的变量用点表达式去调用这个新函数。 我们想强调的是扩展函数是静态分发的,即他们不是根据接收者类型的虚方法。 这意味着调用的扩展函数是由函数调用所在的表达式的类型来决定的, 而不是由表达式运行时求值结果决定的。例如:

fun main() {
    open class Shape

    class Rectangle: Shape()

    fun Shape.getName() = "Shape"

    fun Rectangle.getName() = "Rectangle"

    // 这里声明的是Shape
    fun printClassName(s: Shape) {
        println(s.getName())
    }    

    printClassName(Rectangle())
}
输出为: Shape
因为调用的扩展函数只取决于参数 s 的声明类型,该类型是 Shape 类。

如果一个类定义有一个成员函数与一个扩展函数,而这两个函数又有相同的接收者类型、 相同的名字,并且都适用给定的参数,这种情况总是取成员函数

class Example {
    fun printFunctionType() { println("Class method") }
}

fun Example.printFunctionType() { println("Extension function") }

Example().printFunctionType()

输出结果为:“Class method”。

扩展属性 (真想不到有啥用,如果用估计也是坑)

扩展声明为成员

在一个类内部你可以为另一个类声明扩展。在这样的扩展内部,有多个 隐式接收者 —— 其中的对象成员可以无需通过限定符访问

class Host(val hostname: String) {
    fun printHostname() { print(hostname) }
}

class Connection(val host: Host, val port: Int) {
     fun printPort() { print(port) }

    // 只能内部使用
     fun Host.printConnectionString() {
        // 这里面不用写限定符
         printHostname()   // 调用 Host.printHostname()
         print(":")
         printPort()   // 调用 Connection.printPort()
     }

     fun connect() {
         /*……*/
         host.printConnectionString()   // 调用扩展函数
     }
}

fun main() {
    Connection(Host("kotl.in"), 443).connect()
    //Host("kotl.in").printConnectionString(443)  
    // 错误,该扩展函数在 Connection 外不可用
}

扩展声明所在的类的实例称为 分发接收者,扩展方法调用所在的接收者类型的实例称为 扩展接收者。
对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。要引用分发接收者的成员你可以使用 限定的 this 语法。

class Connection {
    fun Host.getConnectionString() {
        toString()         // 调用 Host.toString()
        this@Connection.toString()  // 调用 Connection.toString()
    }
}

声明为成员的扩展可以声明为 open 并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。

open class Base { }

class Derived : Base() { }

open class BaseCaller {
    open fun Base.printFunctionInfo() {
        println("Base extension function in BaseCaller")
    }

    open fun Derived.printFunctionInfo() {
        println("Derived extension function in BaseCaller")
    }

    fun call(b: Base) {
        b.printFunctionInfo()   // 调用扩展函数
    }
}

class DerivedCaller: BaseCaller() {
    override fun Base.printFunctionInfo() {
        println("Base extension function in DerivedCaller")
    }

    override fun Derived.printFunctionInfo() {
        println("Derived extension function in DerivedCaller")
    }
}

fun main() {
    // “Base extension function in BaseCaller”
    BaseCaller().call(Base())   
    // “Base extension function in DerivedCaller”——分发接收者虚拟解析
    DerivedCaller().call(Base())  
    // “Base extension function in DerivedCaller”——扩展接收者静态解析
    DerivedCaller().call(Derived())  
}