如何在不可变的Kotlin类中创建父子关系

如何在不可变的Kotlin类中创建父子关系,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() sealed class Node {

我有表示树的不可变类,其中子级需要父级引用

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()
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() {
    companion object {
        operator fun invoke(parent: Parent?, childBuilders: List<(Parent) -> Node>): Parent {
            val children = mutableListOf<Node>()
            return Parent(parent, children).apply {
                children.addAll(childBuilders.map { it(this) })
            }
        }
    }
}
密封类节点{
抽象val父:父?
}
班童(
覆盖val父项:父项,
):Node()
班级家长(
覆盖val父项:父项?,
val子项:列表
):Node()

是否有一种惯用的Kotlin方法来创建一个包含正确设置了父引用的子项列表的父项?

另一种方法是从
节点中设置
父项
,并为其提供一个要设置父项的子项列表

sealed class Node(
    children: List<Node> = listOf()
) {
    var parent: Container? = null
        private set

    init {
        (this as? Container)?.apply {
            children.forEach { it.parent = this }            
        }
    }
}

data class Child(val type: String) : Node()

data class Container(
    val children: List<Node>
) : Node(children)
密封类节点(
子项:List=listOf()
) {
变量父级:容器?=null
专用设备
初始化{
(此为?容器)?。应用{
children.forEach{it.parent=this}
}
}
}
数据类子级(val类型:String):节点()
数据类容器(
val子项:列表
):节点(子节点)

唯一的副作用是,
父级
不会被数据类用作属性。

另一种方法是,使父级
节点
内可设置,并为其提供子级列表以设置父级

sealed class Node(
    children: List<Node> = listOf()
) {
    var parent: Container? = null
        private set

    init {
        (this as? Container)?.apply {
            children.forEach { it.parent = this }            
        }
    }
}

data class Child(val type: String) : Node()

data class Container(
    val children: List<Node>
) : Node(children)
密封类节点(
子项:List=listOf()
) {
变量父级:容器?=null
专用设备
初始化{
(此为?容器)?。应用{
children.forEach{it.parent=this}
}
}
}
数据类子级(val类型:String):节点()
数据类容器(
val子项:列表
):节点(子节点)

唯一的副作用是,
parent
不会被数据类用作属性。

与其坚持不可变,不如选择只读。可以将其视为类似于kotlins
MutableList
/
List
。大概是这样的:

sealed class Node {
    abstract val parent: Container?
}

abstract class Child : Node()

abstract class Container : Node() {
    abstract val children: List<Node>
}

private class MutableChild(override var parent: Container?) : Child()

private class MutableContainer(override var parent: Container?, override var children: List<Node>) : Container()

fun buildTree() : Node {
    val children = mutableListOf<Node>()
    val parent = MutableContainer(null, children)
    MutableChild(parent).also { children.add(it) }
    MutableChild(parent).also { children.add(it) }

    return parent
}
密封类节点{
摘要:容器?
}
抽象类子节点:Node()
抽象类容器:节点(){
抽象val子项:列表
}
私有类MutableChild(重写变量parent:Container?:Child()
私有类MutableContainer(覆盖变量父级:Container?,覆盖变量子级:List):Container()
fun buildTree():节点{
val children=mutableListOf()
val parent=MutableContainer(null,子项)
MutableChild(parent).allow{children.add(it)}
MutableChild(parent).allow{children.add(it)}
返回父级
}

与其坚持不变性,不如选择只读。可以将其视为类似于kotlins
MutableList
/
List
。大概是这样的:

sealed class Node {
    abstract val parent: Container?
}

abstract class Child : Node()

abstract class Container : Node() {
    abstract val children: List<Node>
}

private class MutableChild(override var parent: Container?) : Child()

private class MutableContainer(override var parent: Container?, override var children: List<Node>) : Container()

fun buildTree() : Node {
    val children = mutableListOf<Node>()
    val parent = MutableContainer(null, children)
    MutableChild(parent).also { children.add(it) }
    MutableChild(parent).also { children.add(it) }

    return parent
}
密封类节点{
摘要:容器?
}
抽象类子节点:Node()
抽象类容器:节点(){
抽象val子项:列表
}
私有类MutableChild(重写变量parent:Container?:Child()
私有类MutableContainer(覆盖变量父级:Container?,覆盖变量子级:List):Container()
fun buildTree():节点{
val children=mutableListOf()
val parent=MutableContainer(null,子项)
MutableChild(parent).allow{children.add(it)}
MutableChild(parent).allow{children.add(it)}
返回父级
}

我们可以在第一次需要孩子的时候懒洋洋地评估一个构建者列表。注意,只有当代码库的其余部分足够透明时,这才是安全的

sealed class Node {
    abstract val parent: Parent?
}

class Child(
    override val parent: Parent
) : Node()

class Parent(
    override val parent: Parent?,
    private val childBuilders: List<(Parent) -> Node>
) : Node() {

    val children: List<Node> by lazy {
        childBuilders.map { it(this)}
    }
}
密封类节点{
抽象val父:父?
}
班童(
覆盖val父项:父项
):Node()
班级家长(
覆盖val父项:父项?,
private val childBuilders:列表节点>
):Node(){
val儿童:按懒惰列出{
childBuilders.map{it(this)}
}
}

我们可以在第一次需要孩子的时候懒洋洋地评估一个构建者列表。注意,只有当代码库的其余部分足够透明时,这才是安全的

sealed class Node {
    abstract val parent: Parent?
}

class Child(
    override val parent: Parent
) : Node()

class Parent(
    override val parent: Parent?,
    private val childBuilders: List<(Parent) -> Node>
) : Node() {

    val children: List<Node> by lazy {
        childBuilders.map { it(this)}
    }
}
密封类节点{
抽象val父:父?
}
班童(
覆盖val父项:父项
):Node()
班级家长(
覆盖val父项:父项?,
private val childBuilders:列表节点>
):Node(){
val儿童:按懒惰列出{
childBuilders.map{it(this)}
}
}

您可以尝试使用根节点和生成器参数:

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)
您可以允许访问具有扩展属性的潜在子级和/或父级:

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
}
val Node.children:List get()=何时(此){
是Node.Root->children
是Node.Branch->children
是Node.Leaf->emptyList()
}
val Node.parent:节点?get()=当(此){
是Node.Root->null
是Node.Branch->parent
是Node.Leaf->parent
}
因此,您可以导航子体:

fun Node.allChildren(): List<Node> = 
  children + children.flatMap { it.allChildren() }
fun Node.allChildren():列表=
children+children.flatMap{it.allChildren()}
或向上导航:

fun Node.allParents(): List<Node> = 
  listOfNotNull(parent).flatMap { listOf(it) + allParents() }
fun节点。allParents():列表=
listOfNotNull(父).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() }
fun Node.allChildren():序列=
children.asSequence()+children.asSequence().flatMap{it.allChildren()}
有趣的节点。allParents():序列=
listOfNotNull(parent.asSequence().flatMap{sequenceOf(it)+it.allParents()}

注意:注意堆栈溢出

您可以尝试使用根节点和生成器参数:

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)
您可以允许访问具有扩展属性的潜在子级和/或父级:

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
}
val Node.children:List get()=何时(此){
是Node.Root->children
是Node.Branch->children
是Node.Leaf->emptyList()
}
val Node.parent:节点?get()=当(此){
是Node.Root->null
是Node.Branch->parent
是Node.Leaf->parent
}
因此,您可以导航子体:

fun Node.allChildren(): List<Node> = 
  children + children.flatMap { it.allChildren() }
fun Node.allChildren():列表=
children+children.flatMap{it.allChildren()}