使用指针的 Golang 类型断言

7

我一直在为一个层次树界面工作。我的想法是允许具体实现调用.Children(), .Father()和一个函数,可以基于{id, FatherId}结构的切片自动填充层次结构。

我只需要这个接口的三种不同实现,也许对于每个结构体来说整个过程更方便,但我对Go语言很陌生,所以决定使用这个示例来理解接口。

我已经创建了一个类似下面这样的接口:

type Node interface{
    Equals(nodo *Node) bool
    AddChild(child *Node)
    SetFather(father *Node)

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

所以,这个想法是调用一个名为Populate的函数:
func Populate(plainNodes []Node, HierarchichalNodes *[]Node) {}

普通节点是定义其父节点id的项:

{id: "Animal", father: ""}
{id: "Plant", father: ""}
{id: "Mammals", father: "Animal"}

层级节点将是结果:
Animal
|__Mammals

Plant

我遇到的问题是,在尝试在一个具体的结构体中实现接口时,比如这个例子中的"Category"
type Category struct{
    children []Category
    father Category
}

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

请注意,在Category中,我希望与Category的父类和子类一起工作,而不是与接口Node一起工作。
我无法进行转换,会得到:
invalid type assertion: nodo.(*Category) (non-interface type *Node on left)

有什么想法吗?

1
你不应该将接口作为指针传递。指向 *Category 的指针是一个 Node,而不是指向 Node 的指针。 - Not_a_Golfer
2个回答

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

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

此外,如果Category.SetFather()方法想要更改作为接收器标识的Category值,则必须使用指针,否则您将只更改一个在SetFather()返回后将被丢弃的副本。因此请使用像c *Category这样的接收器。

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

更正后的SetFather()方法可能如下所示:

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

如何将SetFather设置为指针接口的方法? - Marcos
@Marcos 当您将SetFather()方法列在Node“下面”时,它将成为Node接口的一个方法。当您声明一个func (c *Category) SetFather(node Node)方法时,那么这个SetFather()就成为了类型*Category(接收器)的一个方法。因此,如果您对Node的所有其他方法执行相同的操作,则类型*Categroy将实现Node,因此可以将类型为*Category的值分配给类型为Node的变量。 - icza
1
指向接口的指针经常被使用。没有它们,Go语言的http包将无法正常运行。 - marsbear
在函数头中不要写node *Node(但如果你想使用指针,可以在其他地方保留指针)。 - marsbear

4

这个应该可以正常工作:

(*nodo).(Category)

先解除引用,再进行断言。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接