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>()
}
没有编译。
是否可以在类体中明确定义属性并仍然能够将实现委托给它?
答案 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