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

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

问题描述:

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

Here is a minimal example that demonstrates the problem:

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 }} ...")
    }
}

从 Java 调用扩展方法很简单:

Calling the extension method from Java is trivial:

Base o = new Derived();
o.extension("hello world", 'l');

但我不知道如何在纯 Kotlin 中做到这一点.StringBase 似乎都没有 extension 方法.

But I can't figure out how to do it in pure Kotlin. Neither String nor Base seems to have the extension method.

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

First, note that an extension function defined as a member requires two receivers, one is an instance of the enclosing class (dispatch receiver, usually this of the enclosing class) and the other is the instance of the type that the function extends (extension receiver). This is documented here.

因此,要从类外部调用这样的函数,您必须提供两个接收器.Kotlin 没有任何语法可以像 (x, "abc").stringExtension(),但您可以使用 扩展 lambda:

So, to call such a function from outside the class you have to provide two receivers. Kotlin doesn't have any syntax to do that explicitly like (x, "abc").stringExtension(), but you can provide the dispatch receiver implicitly using an extension 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()) }
}

(此代码的可运行演示)

with(...) { ... } 块,c 成为隐式接收器,从而允许您将其用作 C 成员扩展中的调度接收器.这适用于任何其他使用带有接收器的函数类型的函数:applyrunuse 等.

In the with(...) { ... } block, c becomes the implicit receiver, thus allowing you to use it as a dispatch receiver in C member extensions. This would work with any other function that uses functional types with receivers: apply, run, use etc.

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

In your case, it would be with(o) { "hello world".extension('l') }

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

As @KirillRakhman noted, an extension receiver of an extension function for C can also be implicitly used as a dispatch receiver for the extensions defined inside C:

fun C.someExtension() = "something".extended()