将任意结构转变为层次结构节点

问题描述 投票:0回答:1

以下示例是基本的节点层次结构实现,我想将其嵌入到其他结构中:

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()
}

所以,当我尝试这个时:

type Foo struct {
    Node
}

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

它惊慌失措:

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

——这是可以理解的。

但是如何让它发挥作用呢?我确实希望将形成层次结构的能力引入任意结构,例如

Foo

go struct hierarchy embedding
1个回答
0
投票

这是一个棘手的问题。

首先让我们看一个简单的方法声明

package main

import "fmt"

type Node struct{}

type NodeInterface any

func (receiver *Node) Method(parameter NodeInterface) {
    var ni NodeInterface = receiver
    _, rok := ni.(*Foo)
    _, pok := parameter.(*Foo)

    fmt.Printf("I'm a %T (castable to *Foo: %v) called with a %T (castable to *Foo: %v)\n", ni, rok, parameter, pok)
}

type Foo struct {
    Node
}

func main() {
    apex := &Foo{}
    apex.Method(apex)
}

这给出了 “我是一个

*main.Node
(可转换为
*Foo
:假),用
*main.Foo
(可转换为
*Foo
:真)”
,在 Go Playground 上尝试一下

好吧,我们知道 -

apex.Method(apex)

(&(*apex).Node).Method(apex)
 的语法糖。

即使接收者是嵌入的,你也不能向下转型,通过指向内部结构的指针会丢失该信息。

另一方面接口保持原有类型。

有效的方法是

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

的语法糖

func main() { apex := &Foo{} cl := &Foo{} (&(*apex).Node).AddChild(&(*cl).Node) (&(*cl).Node).RemoveFromParent() }
在这里您可以添加和删除 

NodeInterface(&(*cl).Node)

(或者 
NodeInterface(&cl.Node)
,如果您愿意的话),这样就可以了。

另一方面,

NodeInterface(cl)

 是不同的值并且不相等。

尝试举例

func (Foo) RemoveFromParent() { fmt.Println("I would prefer rather not to") } func main() { apex := &Foo{} cl := &Foo{} apex.AddChild(cl) cl.RemoveFromParent() }
根本不调用

cl.Node.RemoveFromParent

© www.soinside.com 2019 - 2024. All rights reserved.