gostructhierarchyembedding

Turning arbitrary structs into hierarchy nodes


The following example is basic node hierarchy implementation which I would like to embed into other structs:

package main

import "fmt"

type NodeInterface interface {
    AddChild(child NodeInterface)
    RemoveChild(child NodeInterface)
    RemoveFromParent()
    setParent(parent NodeInterface)
}

type Node struct {
    parent  NodeInterface
    children []NodeInterface
}

func (n *Node) setParent(parent NodeInterface) {
    n.parent = parent
}

func (n *Node) AddChild(child NodeInterface) {
    n.children = append(n.children, child)
    child.setParent(n)
}

func (n *Node) RemoveChild(child NodeInterface) {
    found := false
    var index int
    for i, node := range n.children {
        if node == child {
            found = true
            index = i
            break
        }
    }
    if found {
        n.children = append(n.children[:index], n.children[index+1:]...)
    } else {
        panic(fmt.Sprintf("child not found; given: %T; existing: %T", child, n.children[0]))
    }
}

func (n *Node) RemoveFromParent() {
    n.parent.RemoveChild(n)
}

func main() {
    apex := &Node{}
    cl := &Node{}
    apex.AddChild(cl)
    cl.RemoveFromParent()
}

So, when I try this:

type Foo struct {
    Node
}

func main() {
    apex := &Foo{}
    cl := &Foo{}
    apex.AddChild(cl)
    cl.RemoveFromParent()
}

it panics:

child not found; given: *main.Node; existing: *main.Foo

ā€” which is kind-of understandable.

But how to get it to work? I do want to bring the ability to form hierarchies to arbitrary structs like Foo.


Solution

  • The problem lies in the difference of the entities being compared in this line:

    if node == child {
    

    One is Node, the other is whatever type embeds Node (Foo in this case).

    So, if we make both Node, that will be it. But how?

    Implement getNode():

    func (n *Node) getNode() NodeInterface {
        return n
    }
    

    and then compare Nodes:

    if node.getNode() == child.getNode() {
    

    Full example.