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

我发现了一个有趣的事情,但我做不到。 是否有任何方法使本地扩展方法在接收器的函数中可用。

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(); } 

目前还没有这样的功能,我想在不久的将来也不会被添加。 你应该只使用你的第二个版本。 不关心添加包装类 。 实际上, 避免引入一个包装类的想法,只要你使用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实例。 所以,无论你做什么,只要你使用了本地函数,避免引入一个包装类基本上是没有意义的。 你的第二个解决方案是好的,只是使用它。 它既优雅又高效。

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