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

How do I call extension methods from outside the class they are defined in?

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

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 调用扩展方法很简单:

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

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

您的扩展函数仅在 Base/Derived class 内部定义。参见 Declaring Extensions as Members

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

    fun callExtension(c: Char) {
        "hello".extension(c)
    }
}

fun main(args: Array<String>) {
    val base = Derived()
    base.callExtension('h')
}

首先注意定义为成员的扩展函数需要两个receiver,一个是封闭class的实例(dispatch receiver,通常this 是封闭的 class),另一个是函数扩展类型的实例 (extension receiver)。这已记录在案 here

因此,要从 class 外部调用此类函数,您必须提供两个接收器。科特林 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()) }
}

(runnable demo of this code)

with(...) { ... } 块中,c 成为隐式接收器,因此允许您将其用作 C 成员扩展中的调度接收器。这将适用于任何其他将功能类型与接收器一起使用的功能:applyrunuse

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

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

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

要在 class 之外使用扩展方法,你应该 在 class 中实现它,你应该这样做:

package com.sample.test

import java.io.File

fun File.folderLength() : Long {
    return 0L
}

所以在你的 class 中调用这个方法:

package com.sample.util

import com.sample.test.*
import java.io.File

class foo{
    fun getFolderSize(url: String) : Long{
        var file = new File("...")
        var length = file.folderLength()
        return length
    }
}

希望这对您有所帮助。