Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In go (golang), how can you cast an interface pointer into a struct pointer?

Tags:

go

I want to use some external code that requires a pointer to a struct. At the point that the code is called, I have an interface variable.

When creating a pointer off of that variable, the pointer's type is interface{}* when I need it to be the pointer type of the struct's type.

Image the code in TestCanGetStructPointer does not know about the Cat class, and that it exists in some external package.

How can I cast it to this?

Here is a code sample:

import (
    "reflect"
    "testing"
)   

type Cat struct {
    name string
}

type SomethingGeneric struct {
    getSomething func() interface{}
}

func getSomeCat() interface{} {
    return Cat{}
}

var somethingForCats = SomethingGeneric{getSomething: getSomeCat}

func TestCanGetStructPointer(t *testing.T) {
    interfaceVariable := somethingForCats.getSomething()

    pointer := &interfaceVariable

    interfaceVarType := reflect.TypeOf(interfaceVariable)
    structPointerType := reflect.PtrTo(interfaceVarType)
    pointerType := reflect.TypeOf(pointer)

    if pointerType != structPointerType {
        t.Errorf("Pointer type was %v but expected %v", pointerType, structPointerType)
    }

}

The test fails with:

Pointer type was *interface {} but expected *parameterized.Cat

like image 765
Oved D Avatar asked Mar 23 '15 22:03

Oved D


1 Answers

@dyoo's example does work, but it relies on you to manually cast Dog and Cat.

Here's a bit of a convoluted/verbose example which avoids that constraint somewhat:

package main

import (
    "fmt"
    "reflect"
)

type Cat struct {
    name string
}

type SomethingGeneric struct {
    getSomething func() interface{}
}

func getSomeCat() interface{} {
    return Cat{name: "Fuzzy Wuzzy"}
}

var somethingForCats = SomethingGeneric{getSomething: getSomeCat}

func main() {
    interfaceVariable := somethingForCats.getSomething()
    castVar := reflect.ValueOf(interfaceVariable)
    castVar.Convert(castVar.Type())

    // If you want a pointer, do this:
    fmt.Println(reflect.PtrTo(castVar.Type()))

    // The deref'd val
    if castVar.Type() != reflect.TypeOf(Cat{}) {
        fmt.Printf("Type was %v but expected %v\n", castVar, reflect.TypeOf(&Cat{}))
    } else {
        fmt.Println(castVar.Field(0))
    }
}

Playground Link

like image 181
Momer Avatar answered Oct 06 '22 08:10

Momer