Kotlin使我能够通过委托一个主构造函数参数来实现一个接口,如下所示:
class Foo(xs : ArrayList<Int>) : List<Int> by xs { }
Run Code Online (Sandbox Code Playgroud)
但这向用户展示了支持实施者.委托匿名也似乎没问题:
class Foo() : List<Int> by ArrayList<Int>() { }
Run Code Online (Sandbox Code Playgroud)
这隐藏了实现细节,但是我们无法访问接口未提供的功能,在这种情况下是可变性.
因此,我希望将实现委托给不在主构造函数中的属性.我想拥有的是类似的
class Foo() : List<Int> by xs {
val xs : List<Int> = ArrayList<Int>()
}
Run Code Online (Sandbox Code Playgroud)
哪个不编译.
是否可以在类体中明确定义属性并仍然能够将实现委托给它?
Ale*_*lov 13
目前这不可行.by-clause中的表达式仅在构造类之前计算一次,因此您无法引用该类的符号.
问题跟踪器中有一个请求允许这样做,尽管在Kotlin 1.0中几乎肯定不会支持它.
有时可行的一个有趣的解决方法是使您想要成为委托的属性,而不是使用默认值的构造函数参数.这样它在by-clause和class体中都可以访问:
class Foo(val xs: List<Int> = ArrayList<Int>()) : List<Int> by xs {
fun bar() {
println(xs)
}
}
Run Code Online (Sandbox Code Playgroud)
请记住,虽然xsin by xs仍然只在这里计算一次,所以即使xs是var属性,也只使用构造函数中提供的默认值.它不是一个通用的解决方案,但有时它可以提供帮助.
扩展 Alexander Udalov 的答案,我想出了一个使用私有基类的解决方案
private open class FooBase(protected val xs : MutableList<Int>) : List<Int> by xs { }
class Foo() : FooBase(ArrayList()) {
fun bar() {
xs.add(5)
}
}
Run Code Online (Sandbox Code Playgroud)
现在我可以访问支持我的接口实现的属性,但不受该接口提供的操作的限制,同时仍然对用户隐藏实际实现。
注意:虽然它有效,但我从EXPOSED_SUPER_CLASS检查中得到的 IntelliJ IDEA 15 CE 收到以下警告:已弃用:子类有效可见性 'public' 应该与其超类有效可见性 'private' 相同或更少宽松。我不太确定这里不推荐使用的部分是什么意思——警告是否会在未来被删除,或者在某些时候不会编译。无论如何,我们真的不必使用private open类,abstract或者干脆open就可以使用,因为即使允许用户创建 的实例FooBase,他也无能为力。
实际上有一个简单而紧凑的解决方案,它不使用任何可疑行为:
class Foo private constructor(private val xs: ArrayList<Int>) : List<Int> by xs {
constructor() : this(ArrayList<Int>()) { }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1625 次 |
| 最近记录: |