如何将实现委托给Kotlin中的属性?

时间:2015-11-27 23:56:08

标签: kotlin

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>()
}

没有编译。

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

2 个答案:

答案 0 :(得分:12)

目前无法实现。 by - 子句中的表达式只在构造类之前计算一次,因此您不能引用该类的符号。

有一个request in the issue tracker允许这样做,虽然它几乎肯定不会在Kotlin 1.0中得到支持。

有时工作的一个有趣的解决方法是使您想要成为委托的属性,而不是默认值的构造函数参数。这样,它就可以在by - 子句和类体中访问:

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

请注意,xs中的by xs仍然只在这里计算过一次,所以即使xs属于var属性,也只会提供默认值将使用构造函数。这不是一个通用的解决方案,但有时它可以提供帮助。

答案 1 :(得分:4)

扩展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检查:不推荐使用:子类有效可视性&#39;公共&# 39;应该与其超类有效可见性&#39; private&#39; 相同或更不宽容。我不太清楚弃用的部分是什么意思 - 将来是否会删除警告,或者在某些时候不会编译。无论如何,我们真的不必使用private open类,abstract或只是open会这样做,因为即使允许用户创建{{1}的实例他无能为力。

更新

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

FooBase