如何在接收器的功能中使用本地扩展方法?

时间:2017-06-20 07:19:43

标签: scope kotlin extension-methods

我发现了一件有趣的事情,但我无法做到。有没有办法在带接收器的函数中使本地扩展方法可用。

val list = ArrayList<Any>();

fun <T> Array<T>.bind(context: MutableList<in T>, block: Array<T>.() -> Unit) {
    fun Array<T>.save() {
        context.addAll(this);
    }
    block();
}

arrayOf(1, 2, 3).bind(list) {
    save(); //todo: how to bind extension in execution scope
};

我知道通过为接收器引入另一种类型有另一种方法,但我想避免它。例如:

interface Savable {
    fun save();
}

fun <T> Array<T>.bind(context: MutableList<in T>, block: Savable.() -> Unit) {
    val proxy = object : Savable {
        override fun save() {
            context += this@bind;
        }
    };

    proxy.block();
}

1 个答案:

答案 0 :(得分:0)

还没有这样的功能,我认为在不久的将来它也不会被添加。 您应该使用第二个版本。不要在乎添加包装类。实际上,避免引入包装类的想法是,只要您使用JVM后端,只需无意义,因为通过使用本地函数,您实际上是在添加本地类。

这是您的kotlin函数的等效Java代码,在您按照建议修复之后,假设您的bind函数存在于文件bind.kt中:

public final class BindKt {
    public static <T> void bind(T[] receiver, List<? super T> context, Function1<T> block) {
        class Local { // the name of local class is unimportant, as it's generated by compiler. It should looks like "package.name.BindKt$bind$X" where X is a number.
            public void save(T[] receiver) {
                context.addAll(receiver);
            }
        }
        block.invoke(this); // this won't compile. Neither will yours.
    }
}

正如您所看到的,save未编译为静态方法,这意味着,如果block以某种方式调用save,则Local的实例必须为拳头创造。所以,无论你做什么,只要你使用本地函数,基本上没有必要避免引入包装类。你的第二个解决方案是好的,只需使用它。它既优雅又高效。

如果您真的不想添加类/对象创建,请将这些扩展函数移动到包范围,然后让客户端导入它们。