【问题标题】:How can I delegate an implementation to a mutable property in Kotlin?如何将实现委托给 Kotlin 中的可变属性?
【发布时间】:2018-06-11 18:06:09
【问题描述】:

据我了解,在 Kotlin 中委派实现的想法是避免出现如下代码:

class MyClass(val delegate : MyInterface) : MyInterface
{
    override fun myAbstractFun1() = delegate.myAbstractFun1()
    override fun myAbstractFun2() = delegate.myAbstractFun2()
    // ...
}

相反,我们可以编写以下代码来做同样的事情:

class MyClass(val delegate : MyInterface) : MyInterface by delegate

现在,我希望 delegate 成为可变变量,即我的代码如下所示:

var delegate : MyInterface = MyImplementation()
object MyObject : MyInterface by delegate

因此,如果我像第一个示例一样将每个抽象方法委托给delegate,那么更改delegate 的值确实会改变方法的行为。但是,上面的代码编译成这个 Java 代码:

public final class MyObject implements MyInterface {
    public static final MyObject INSTANCE;
    // $FF: synthetic field
    private final MyInterface $$delegate_0 = MyObjectKt.access$getDelegate$p();

    @NotNull
    public String myAbstractFun1() {
        return this.$$delegate_0.myAbstractFun1();
    }

    @NotNull
    public String myAbstractFun2() {
        return this.$$delegate_0.myAbstractFun2();
    }
}

所以很明显,Kotlin 编译器决定在创建 MyObject 时将其复制到最终字段 $$delegate_0 中,而不是仅使用 delegate 字段,而当我更改 delegate 的值时,该字段不会被修改

有没有更好的解决方案来代替手动委派每个方法?

【问题讨论】:

  • 这个的用例是什么?
  • @Todd 我正在尝试拥有一个全局对象来保存我的库的配置以及提供修改它的方法。我知道有不同的方法可以实现这一点,但这似乎是一种方便的方式,可以在一个地方拥有属性和方法,而无需创建包装类
  • 如果通过正确的object,它甚至不起作用!看来编译器真的非常想知道静态会发生什么。我认为这也有道理;如果你自己实现了这些方法,它们在运行时不会改变(除非反射),所以为了有类似的保证,编译器需要修复委托。
  • @Raphael 我不明白这有什么意义,因为当实例变量发生变化时,手动实现的方法可以改变 bedaviour。那么为什么自动生成的方法不应该也是这样呢?
  • 查看(并投票)youtrack.jetbrains.com/issue/KT-83

标签: java delegates kotlin delegation


【解决方案1】:

遗憾的是,据我所知,无法通过更改原始属性内容来更改委托,但是您仍然可以通过以不可变的方式工作并复制来做类似的事情对象:

interface MyInterface {
  fun foo():Int
}

data class MyClass(val delegate : MyInterface) : MyInterface by delegate

object ImplementationA: MyInterface { override fun foo() = 7 }
object ImplementationB: MyInterface { override fun foo() = 5 }

val objA = MyClass(ImplementationA)
println(objA.foo()) // returns 7

val objB = objA.copy(ImplementationB)
println(objB.foo()) // returns 5
println(objA.foo()) // still 7

希望这仍然有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2013-03-08
    • 2018-05-07
    • 2017-12-22
    • 2015-09-02
    • 1970-01-01
    • 2020-05-24
    相关资源
    最近更新 更多