如何从定义的类之外调用扩展方法?

fre*_*low 8 extension-methods kotlin

这是一个演示问题的最小示例:

abstract class Base {
    abstract fun String.extension(x: Char)
}

class Derived : Base() {
    override fun String.extension(x: Char) {
        // Calling lots of methods on String, hence extension method
        println("${first()} $length ${last()} ${firstOrNull { it == x }} ...")
    }
}
Run Code Online (Sandbox Code Playgroud)

从Java调用扩展方法是微不足道的:

Base o = new Derived();
o.extension("hello world", 'l');
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何在纯Kotlin中做到这一点.似乎也String没有Base这种extension方法.

hot*_*key 15

首先,请注意定义为成员的扩展函数需要两个接收器,一个是封闭类的实例(调度接收器,通常this是封闭类),另一个是函数扩展的类型的实例(扩展接收器) .这在此处记录.

因此,要从课外调用此类函数,您必须提供两个接收器.Kotlin 没有任何语法可以明确地表达(x, "abc").stringExtension(),但你可以使用扩展lambda隐式地提供调度接收器:

class C(val name: String) {
    fun String.extended() = this + " extended by " + name
}

fun main(args: Array<String>) {
    val c = C("c")
    with(c) { println("abc".extended()) }
}
Run Code Online (Sandbox Code Playgroud)

(此代码的runnable演示)

with(...) { ... }块中,c成为隐式接收器,从而允许您将其用作C成员扩展中的调度接收器.:这与使用功能类型与接收器的其他功能工作apply,run,use等.

在你的情况下,它会 with(o) { "hello world".extension('l') }

正如@KirillRakhman所指出的,扩展函数的扩展接收器C也可以隐式地用作内部定义的扩展的调度接收器C:

fun C.someExtension() = "something".extended()
Run Code Online (Sandbox Code Playgroud)