【问题标题】:How to make a local extension method avaiable in a function with receiver?如何在带有接收器的函数中使用本地扩展方法?
【发布时间】:2017-11-22 14:27:39
【问题描述】:

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

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

【问题讨论】:

  • 我很难理解您想要达到的目标。能给个用例吗?
  • @KirillRakhman 先生。确实,如果您熟悉 ruby,此功能并不新鲜。它可以动态地将其他方法添加到object 范围而不是class 范围。假设我们有一个Entity 类,我希望将CURD 方法绑定到某个对象而不是类级别。
  • 另一种选择可能是将保存函数作为参数传递给block
  • @marstran 这个想法不错,但是当我们有超过六个扩展方法时如何处理?
  • 如果你想这样做,我认为你应该介绍你的界面。

标签: scope kotlin extension-methods


【解决方案1】:

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

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

【讨论】:

  • 首先,感谢您的回答。但是如果您将C 替换为T 并在我的问题中删除通用参数C,则代码可以编译。我知道永远不会使用本地扩展方法,但我希望它在 lambda 范围内可用。
  • 我添加并突出显示了 anwser 的某些部分。请仔细阅读。本地扩展功能应该移动到包范围或移动到包装器类中,就像您的第二个解决方案一样。
猜你喜欢
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 2019-02-03
  • 1970-01-01
  • 1970-01-01
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多