如何将Kotlin的默认属性值设置为`this`
我有下面的代表简单树的类结构。 每个项目可以有多个孩子和父母。
树根虽然让我头痛。 我想这样做,而不使用null
所以我可以通过调用item.parent
向上遍历树。 为了简化它,我希望根本身是一个父类,但是我不知道如何去做。
interface Item { val parent: Directory } interface ItemWithChildren{ val children: MutableList } class Directory() : Item, ItemWithChildren { override val children: MutableList = mutableListOf() override val parent: Directory by lazy { this } constructor(par: Directory) : this() { parent = par //Error: val cannot be reassigned } } class File(override val parent: Directory) : Item
该代码无法编译,因为无法重新分配val parent
。 但是使用this
作为默认的参数值也是不可能的。 有什么出路吗?
如果我允许父母是可空的,那么解决方案很简单。 但是,如果可能的话,我不想使用空值。 也null
将击败item.parent
链。
你可以使用一个init
块。 例如:
class Directory(parent: Directory? = null) : Item, ItemWithChildren { override val children: MutableList- = mutableListOf() override val parent: Directory init { this.parent = parent ?: this } }
或者,你可以为“root”创建一个单独的“父”实现。 例如:
interface ChildItem /* renamed from `Item` for clarity */ { val parent: ParentItem } interface ParentItem /* renamed from `ItemWithChildren` for clarity */ { val children: MutableList } class Root() : ParentItem { override val children: MutableList = mutableListOf() } class Directory(override val parent: ParentItem) : ChildItem, ParentItem { override val children: MutableList = mutableListOf() } class File(override val parent: ParentItem) : ChildItem
这样,你的“根”项目没有类似于你的“叶子”(“文件”)项目没有children
属性的parent
项属性。 你可能也想让你的ChildItem
和ParentItem
接口扩展一个通用的接口(例如命名的Item
)。
@ mfulton26回答了如何以你严格要求的方式来做到这一点。 但对于其他人可能想知道这个选择,他们仍然应该考虑在Kotlin这种types的工作的null
值是可以的。
您可以拥有一个null
属性和一些派生属性,允许将访问声明为非null
。 因为无论哪种方式(你的计划避免null
或接受和使用null
),你将不得不问“ 我有一个父母吗? ”这几乎是要求“ 是父母null? ”那么为什么一个不常见的“可能无休止的循环造成“这个案件的解决办法?
如果我的树类是这样的:
data class Something(val text: String, val parentOrNull: Something? = null) { val parent: Something get() = parentOrNull!! val hasParent = parentOrNull != null }
然后,我有选择如何访问父和无担心null
:
val root = Something("rooty") val child = Something("youngun", root) val leaf = Something("baby", child) fun printPathToNode(node: Something) { // use derived properties to check and not worry about the null if (node.hasParent) printPathToNode(node.parent) println(node) } fun findRoot(node: Something): Something { // use null operators to not worry about the null return node.parentOrNull?.let { findRoot(it) } ?: node }
那么你可以看到它运行良好,输出良好,没有null
问题:
printPathToNode(leaf) // rooty, youngun, baby printPathToNode(child) // rooty, youngun printPathToNode(root) // rooty println(findRoot(leaf)) // rooty println(findRoot(child)) // rooty println(findRoot(root)) // rooty
在没有意义的情况下,应该避免使用空值。 但有时他们实际上是一个合理的选择。 Kotlin可以帮助保护你,当你有可以为空的价值以及了解他们,而不是假装一切都OK。 然后,它给你很好的空运算符,以帮助你与他们合作。
这就是我将使用@ mfulton的答案:
class Directory(parent: Directory? = null) : Item, ItemWithChildren { override val children = mutableListOf- () override val parent = parent ?: this }