8

I've been working in an interface to use as a hierarchical tree. The idea is to aloud the concrete implementations to call .Children(), .Father() and a function to auto populate the hierarchy based on a slice of {id, FatherId} schema.

I only need three different implementations of this interface, maybe it's more convenient to do the whole thing for each struct but I'm new to Go and decided to use this example to understand interfaces.

I've come to an interface that looks something like this:

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

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

So the idea is call a Populate function:

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

Plain nodes would be items defining the id of his father:

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

Hierarchical nodes would be the result:

Animal
|__Mammals

Plant

The problem I'm getting is when I try to implement the interface in a concrete struct, this case "Category".

type Category struct{
    children []Category
    father Category
}

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

Notice that in Category I want to work with Category father and children, not with interface Node.

I can't do the conversion, I get :

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

Any ideas?

1
  • 1
    you shuoldn't pass interfaces as pointers. a pointer to *Category is a Node, not a pointer to Node. Commented Oct 5, 2016 at 12:13

2 Answers 2

8

Your parameter is node *Node, it is of type *Node. Node is an interface type, but *Node is not: it is a pointer to interface.

Don't use pointer to interface, it is very rarely needed. Instead change it to node Node. Also change all your other *Node pointers to just Node.

Also if Category.SetFather() method intends to change the Category value identified as the receiver, it must be a pointer else you'd only end up changing a copy which will be discarded after SetFather() returns. So use a receiver like c *Category.

Going further, if the node argument contains a *Category wrapped in an interface, you can't directly assign it to Category.father as that is a non-pointer type Category. You need a pointer indirection, e.g. c.father = *v; or change the type of the father field to be a pointer: father *Category.

Corrected SetFather() method could look like this:

func (c *Category) SetFather(node Node) {
    if v, ok := node.(*Category); ok {
        c.father = *v
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

How do I make SetFather a method of the (pointer?) interface?
@Marcos When you list the SetFather() method "under" Node, then it will be a method of the Node interface. When you declare a func (c *Category) SetFather(node Node) method, then this SetFather() becomes a method of the type *Category (the receiver). So if you do the same with all other methods of Node, then the type *Categroy will implement Node and so a value of type *Category can be assigned to a variable of type Node.
Pointers to interfaces are used quite often. The http-package of Go wouldn't work without them.
Just don't write node *Node in the function header (but keep the pointers elsewhere if you want to work with pointers).
4

This should work:

(*nodo).(Category)

De-reference first, assert afterwards.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.