Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang type assertion with pointers

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?

like image 997
Marcos Avatar asked Oct 05 '16 11:10

Marcos


People also ask

What is a type assertion in Golang?

yourbasic.org/golang A type assertion provides access to an interface’s concrete value. Type assertions Type switches Type assertions A type assertiondoesn’t really convert an interfaceto another data type, but it provides access to an interface’s concrete value, which is typically what you want.

How do you initialize a pointer in Golang?

Pointers Initialization in Go The pointers of a type are initialized using the address-of (&) operator on a subject of that specific type. Here is the way to do it. 4. Go Pointers dereferencing Dereferencing a pointer means getting the value inside the address the pointer holds.

What is a pointer in Go language?

A pointer is a variable that stores the address it points to. A pointer of a specific type can only point to that type. 2. GoLang Pointer syntax The syntax for the pointers is really simple.

Why do we need type assertions in go?

Type assertions allow us to access the data and data type of values stored by the interface. Before we learn about type assertions, let's see why we need type assertions in Go. We know that an empty interface can accept any type and number of values. For example,


2 Answers

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
    }
}
like image 126
icza Avatar answered Sep 20 '22 02:09

icza


This should work:

(*nodo).(Category)

De-reference first, assert afterwards.

like image 42
marsbear Avatar answered Sep 17 '22 02:09

marsbear