kotlin - 如何在不可变的 Kotlin 类中创建父子关系
问题描述
我有代表树的不可变类,其中孩子需要父引用。
sealed class Node {
abstract val parent: Parent?
}
class Child(
override val parent: Parent,
) : Node()
class Parent(
override val parent: Parent?,
val children: List<Node>
) : Node()
是否有一种惯用的 Kotlin 方法来创建具有正确设置父引用的子列表的父对象?
解决方案
您可以尝试使用根节点和构建器参数:
sealed class Node {
data class Root(
val createChildren: ParentList.() -> Unit
) : Node() {
val children: List<Node> = ParentList(this).apply(createChildren)
}
data class Branch(
val createChildren: ParentList.() -> Unit,
val parent: Node
) : Node() {
val children: List<Node> = ParentList(this).apply(createChildren)
}
data class Leaf(
val parent: Node
) : Node()
}
class ParentList(
val parent: Node,
private val children: MutableList<Node> = mutableListOf()
) : List<Node> by children {
fun branch(createChildren: ParentList.() -> Unit) {
children += Node.Branch(createChildren, parent)
}
fun leaf() {
children += Node.Leaf(parent)
}
}
fun root(createChildren: ParentList.() -> Unit) = Node.Root(createChildren)
它们可以像下面这样构造(可能需要向任一节点添加额外的细节):
fun usage() {
val graph = root {
branch {
leaf()
}
branch {
branch {
leaf()
}
leaf()
}
}
}
您可以允许访问具有扩展属性的潜在孩子和/或父母:
val Node.children: List<Node> get() = when(this) {
is Node.Root -> children
is Node.Branch -> children
is Node.Leaf -> emptyList()
}
val Node.parent: Node? get() = when(this) {
is Node.Root -> null
is Node.Branch -> parent
is Node.Leaf -> parent
}
所以你可以导航后代:
fun Node.allChildren(): List<Node> =
children + children.flatMap { it.allChildren() }
或向上导航:
fun Node.allParents(): List<Node> =
listOfNotNull(parent).flatMap { listOf(it) + allParents() }
为了避免在进行可能提前完成的搜索时进行评估,您始终可以使用序列而不是列表:
fun Node.allChildren(): Sequence<Node> =
children.asSequence() + children.asSequence().flatMap { it.allChildren() }
fun Node.allParents(): Sequence<Node> =
listOfNotNull(parent).asSequence().flatMap { sequenceOf(it) + it.allParents() }
注意:注意 Stackoverflows
推荐阅读
- ios - 如何按数字和字母值快速对字符串数组进行排序?
- visual-studio - ImportError:在终端中运行时没有名为 bs4 的模块
- jwt - 带有 RS256 加密 JWT 的 PostGraphile“无效算法”错误
- .net-core - ws-federation dotnet core 没有对 wsignoutcleanup1.0 做任何事情
- sql - 如何显示由于服务更改而重复的值的单个项目列表
- excel - VBA中的Countif函数与动态标准
- c++ - 这两个函数的操作顺序是什么
- sql - 在 MS ACCESS 中使用 SELF JOIN 对多列求和
- snowflake-cloud-data-platform - Snowflake 是否在集群中的多个节点或单个节点上执行“单个”单个查询?
- css - 下拉导航