我一直在一个界面中用作层次树。这个想法是大声地调用.Children().Father()的具体实现,以及一个基于{id, FatherId}模式切片自动填充层次结构的函数。

我只需要此接口的三种不同实现,也许对每个结构进行整个操作会更方便,但是我是Go语言的新手,因此决定使用此示例来了解接口。

我来到一个看起来像这样的界面:

1
2
3
4
5
6
7
8
type Node interface{
    Equals(nodo *Node) bool
    AddChild(child *Node)
    SetFather(father *Node)

    Children() []Node
    Father() *Node
}

所以这个想法叫做Populate函数:

1
func Populate(plainNodes []Node, HierarchichalNodes *[]Node) {}

普通节点将是定义其父亲ID的项目:

1
2
3
{id:"Animal", father:""}
{id:"Plant", father:""}
{id:"Mammals", father:"Animal"}

分层节点将是结果:

1
2
3
4
Animal
|__Mammals

Plant

我遇到的问题是当我尝试在具体的结构(本例为"Category")中实现接口时。

1
2
3
4
5
6
7
8
9
type Category struct{
    children []Category
    father Category
}

func (c Category) SetFather(node *Node) {
    v, ok = node.(*Category)
    c.father = v
}

请注意,在Category中,我想与Category父亲和孩子一起工作,而不是与接口Node一起工作。

我无法进行转换,我得到:

1
invalid type assertion: nodo.(*Category) (non-interface type *Node on left)

有任何想法吗?

  • 您应该将接口传递为指针。 指向*Category的指针是Node,而不是指向Node的指针。

您的参数为node *Node,其类型为*NodeNode是接口类型,但是*Node不是:它是指向接口的指针。

不要使用指向接口的指针,这很少需要。 而是将其更改为node Node。 同时将所有其他*Node指针更改为Node

同样,如果Category.SetFather()方法打算更改标识为接收方的Category值,则它必须是一个指针,否则最终只会更改一个副本,该副本在SetFather()返回后将被丢弃。 因此,请使用c *Category之类的接收器。

更进一步,如果Node参数包含包装在接口中的*Category,则不能将其直接分配给Category.father,因为这是非指针类型Category。 您需要指针间接寻址,例如 c.father = *v; 或将father字段的类型更改为指针:father *Category

已更正的SetFather()方法如下所示:

1
2
3
4
5
func (c *Category) SetFather(node Node) {
    if v, ok := node.(*Category); ok {
        c.father = *v
    }
}
  • 如何使SetFather成为(指针?)接口的方法?
  • @Marcos当您在Node下列出SetFather()方法时,它将是Node接口的方法。 声明func (c *Category) SetFather(node Node)方法时,此SetFather()成为类型为*Category的方法(接收方)。 因此,如果对Node的所有其他方法执行相同操作,则类型*Categroy将实现Node,因此可以将类型为*Category的值分配给类型为Node的变量。
  • 指向接口的指针经常使用。 没有它们,Go的http软件包将无法工作。
  • 只是不要在函数头中写节点* Node(但是如果要使用指针,则将指针保留在其他位置)。

这应该工作:

1
(*nodo).(Category)

首先解除引用,然后进行比较。