【问题标题】:How to delegate implementation to a property in Kotlin?如何将实现委托给 Kotlin 中的属性?
【发布时间】:2015-12-16 04:08:48
【问题描述】:

Kotlin 使我能够通过委托给主构造函数参数来实现接口,如下所示:

class Foo(xs : ArrayList<Int>) : List<Int> by xs { }

但这向用户展示了支持实现者。委托给匿名似乎也可以:

class Foo() : List<Int> by ArrayList<Int>() { }

这隐藏了实现细节,但我们失去了对接口未提供的功能的访问权限,在这种情况下是可变性。

因此,我想将实现委托给不在主构造函数中的属性。我想要的类似于

class Foo() : List<Int> by xs {
    val xs : List<Int> = ArrayList<Int>()
}

无法编译。

是否可以在类主体中明确定义一个属性,并且仍然能够将实现委托给它?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    目前这是不可能的。 by-clause 中的表达式在构造类之前只计算一次,因此您不能引用该类的符号。

    request in the issue tracker 允许这样做,尽管 Kotlin 1.0 几乎肯定不会支持它。

    有时 起作用的一个有趣的解决方法是,将您想成为委托的属性改为具有默认值的构造函数参数。这样它就可以在by-clause 和类主体中访问:

    class Foo(val xs: List<Int> = ArrayList<Int>()) : List<Int> by xs {
        fun bar() {
            println(xs)
        }
    }
    

    请记住,尽管by xs 中的xs 在此处仍然只计算一次,因此即使xs 是var 属性,也只会使用构造函数中提供的默认值。这不是一个通用的解决方案,但有时会有所帮助。

    【讨论】:

      【解决方案2】:

      扩展 Alexander Udalov 的答案,我想出了一个使用私有基类的解决方案

      private open class FooBase(protected val xs : MutableList<Int>) : List<Int> by xs { }
      
      class Foo() : FooBase(ArrayList()) {
          fun bar() {
              xs.add(5)
          }
      }
      

      现在我可以访问支持我的接口实现的属性,但不限于该接口提供的操作,同时仍向用户隐藏实际实现。

      注意:虽然它有效,但我从 IntelliJ IDEA 15 CE 收到以下警告,该警告来自 EXPOSED_SUPER_CLASS 检查:已弃用:子类有效可见性“公共”应相同或比它的超类有效可见性“private”更宽松。我不太确定这里的 deprecated 部分是什么意思 - 警告是否会在将来被删除,或者这不会在某些时候编译。无论如何,我们真的不必使用private open 类,abstract 或简单的open 都可以,因为即使允许用户创建FooBase 的实例,他也无能为力用它。

      更新:

      实际上有一个简单而紧凑的解决方案,不使用任何可疑行为:

      class Foo private constructor(private val xs: ArrayList<Int>) : List<Int> by xs {
          constructor() : this(ArrayList<Int>()) { }
      }
      

      【讨论】:

      • 我很好奇为什么会发生这种弃用。在这种情况下,我也会收到同样的信息。动机是什么?
      猜你喜欢
      • 2018-06-11
      • 1970-01-01
      • 2018-05-07
      • 2017-12-22
      • 2015-09-02
      • 1970-01-01
      • 2020-05-24
      • 2017-01-18
      • 1970-01-01
      相关资源
      最近更新 更多