生成的setter与接口方法发生冲突

问题描述 投票:3回答:2

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

private class Foo : IFoo {
        var selected = false

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

    }

然而编译器抱怨,因为Kotlin为selected生成了一个setter,这两个方法发生冲突:

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

  • 我想删除自定义方法以利用setter,但是它没有标记为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重命名为例如dataSelected以便生成的setter不会与方法冲突,但应该有一种方法来保持这个简单的属性名称并按预期实现接口。
  • Is there a way to ask the Kotlin compiler to not generate a setter for this property, or to have it marked as override?

    kotlin properties getter-setter generated-code
    2个回答
    1
    投票

    您可以创建没有支持字段的属性,然后覆盖您的抽象函数,如下所示:

    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而不是属性本身。

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

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

    而不是这个:

    Foo().setSelected(true)
    

    你的setter可能会做一些其他的东西(比如打印日志),这可能有副作用,所以你需要确保你调用正确的setter。这有时候有点棘手,因为Kotlin总是为每个可变变量(var)创建一个setter。


    1
    投票

    你可以use @JvmName to rename the generated setter

    private class Foo : IFoo {
        @set:JvmName("setSelected0")
        var selected = false
    
        override fun setSelected(isActive: Boolean) {
            selected = isActive
        }
    }
    

    使用Kotlin保持不变。

    © www.soinside.com 2019 - 2024. All rights reserved.