接口中的属性不能有支持字段

Posted

技术标签:

【中文标题】接口中的属性不能有支持字段【英文标题】:Property in interface cannot have a backing field 【发布时间】:2017-04-26 08:45:32 【问题描述】:

我正在学习Kotlin。我的代码如下:

   interface BaseLogicDecoupler<A : BaseViewNotifier, B : BaseScreenRouter> 

        var notifier: A?
        var router: B?

        fun attachNotifier(notifier: A?) 
            this.notifier = notifier
        

        fun detachNotifier() 
            notifier = null;
        

        fun attachRouter(router: B?) 
            this.router = router
        

        fun detachRouter() 
            router = null;
        
    

但是当我更改它并尝试为属性提供访问器时,如下所示:

var notifier: A?
    get() = notifier 

编译时出现错误提示:

从文档here 来看,kotlin 接口可以提供实现,并且可以具有带有访问器的属性。为什么编译失败?

我无法理解错误。它说什么?谁能简单的解释一下?

【问题讨论】:

【参考方案1】:

这是一个意想不到的角落案例,感谢您找到它。

让我简要解释一下发生了什么。为了简单起见,我将使用剥离接口A 和类B

interface A 
    var notifier: Int

通常,类中的 var 属性包括 3 个组件:用于存储其值的私有 backing field、用于写入它的 setter 方法和用于读取它的 getter 方法。但是一个接口不能有一个字段(因为 live 很痛苦,如果有的话,一些数学不会加起来),所以接口中的 var 属性只包含两个组件:settergetter

如上所述,我们的接口 A 声明了 2 个方法:settergetter,两者都没有实现。让我们为其添加一些实现:

interface A2 
    var notifier: Int
        get() return 1
        set(v) 

到目前为止,一切都很好。两个带有实现的open 方法,它们都不使用任何字段。但是如果只声明了一个实现呢?

interface A3 
    var notifier: Int    //ERROR: Property in an interface cannot have a backing field
        get() return 1
        //set(v) 

事实证明,如果您仅指定 getter,Kotlin 还会为该属性生成(默认)setter。换句话说,A3A4 相似:

interface A4 
    var notifier: Int
        get() return 1
        set(v) field = v  //Obviously an error

这可能是错误或预期行为。这是问题单:https://youtrack.jetbrains.com/issue/KT-15193

可能的解决方法:

A2 中声明一个适当的setter 使用abstract class 而不是接口

【讨论】:

我最终使用了抽象类。但令人沮丧的是,我在任何地方都找不到任何文档。谢谢你的回答。 如果您在 JetBrains 问题跟踪器上报告,请不要忘记在此处给我发送链接。谢谢! 太棒了!非常感谢。 您可以使用 val 代替 var (如果它适合您的目的),只需定义 get() 而不使用 set()(案例 A3) 对该问题进行了投票。两年多过去了,它仍然困扰着 Kotlin。

以上是关于接口中的属性不能有支持字段的主要内容,如果未能解决你的问题,请参考以下文章

vs中interface含义

接口和抽象类的区别

抽像类与接口

Java的类与接口有什么作用?支持多继承吗?

C# 类 - 接口 Interface

Go面向对象