首页 > 解决方案 > 生成的 setter 与接口方法冲突

问题描述

我正在编写一个实现公开setSelected方法的接口的类。这个类将有一个selected属性:

private class Foo : IFoo {
        var selected = false

        override fun setSelected(isActive: Boolean) {
            selected = isActive
        }

    }

然而,编译器抱怨说,当 Kotlin 为 生成一个 setter 时selected,这两种方法会发生冲突:

Error:(14, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
    fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
    fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
Error:(24, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
    fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
    fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo

  • 我很想删除自定义方法来利用设置器,但是它没有被标记override,所以我的类没有完全实现接口:

    Error:(11, 13) Kotlin: [com.bar.jvmTest] Class 'Foo' is not abstract and does not implement abstract member public abstract fun setSelected(isActive: Boolean): Unit defined in bar.baz
    

  • 我知道我可以重命名selected为 egdataSelected以便生成的 setter 不会与方法发生冲突,但是应该有一种方法可以保留这个简单的属性名称并按预期实现接口。
  • 有没有办法让 Kotlin 编译器不为此属性生成设置器,或者将其标记为override

    标签: kotlinpropertiesgetter-settergenerated-code

    解决方案


    您可以创建一个没有支持字段的属性,然后像这样覆盖您的抽象函数:

    class Foo : IFoo {
      private var hiddenSelected = false
    
      val selected get() = hiddenSelected
    
      override fun setSelected(isActive: Boolean) {
        hiddenSelected = isActive
      }
    }
    

    更新:

    睡了之后,我认为这个解决方案一点也不好,原因有两个:

    1. hiddenSelected它引入了一个不必要的新字段 ( )
    2. 您不能使用标准 Kotlin 方式(=运算符)对该字段进行分配

    我认为最好的解决方案是:

    class Foo : IFoo {
      @set:JvmName("setSelected0")
      var selected: Boolean = false
        set(value) { setSelected(value) }
    
      override fun setSelected(isActive: Boolean) {
        // Possibly some other stuff
        println("Now i'm using my own setter!")
        selected = isActive
      }
    }
    

    使用注解@JvmName您可以告诉编译器如何命名该特定函数。Kotlin 会自动为每个属性创建一个 getter 和 setter,因此您需要使用set:修饰符来注释该属性的 setter 而不是属性本身。

    此外,为该属性实现自定义设置器非常重要,这样您就可以安全地编写以下代码:

    Foo().selected = true // This also prints "Now i'm using my own setter!"
    

    而不是这个:

    Foo().setSelected(true)
    

    您的 setter 可能会做一些其他事情(例如打印该日志),这可能会产生副作用,因此您需要确保调用正确的 setter。这有时会有点棘手,因为 Kotlin 总是为每个可变变量 ( var) 创建一个 setter。


    推荐阅读