简体   繁体   中英

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

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

@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

The following may help: http://play.golang.org/p/XkdzeizPpP

package main

import (
    "fmt"
)

type Cat struct {
    name string
}

type Dog struct {
    name string
}

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

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

func getSomeDog() interface{} {
    return Dog{name: "fido"}
}

var somethings = []SomethingGeneric{
    SomethingGeneric{getSomething: getSomeCat},
    SomethingGeneric{getSomething: getSomeDog},
}

func main() {
    for _, something := range somethings {
        interfaceVariable := something.getSomething()

        cat, isCat := interfaceVariable.(Cat)
        dog, isDog := interfaceVariable.(Dog)

        fmt.Printf("cat %v %v\n", cat, isCat)
        fmt.Printf("dog %v %v\n", dog, isDog)
    }
}

I found this thread: https://groups.google.com/forum/#!topic/golang-nuts/KB3_Yj3Ny4c

package main

import (
    "fmt"
    "reflect"
)

type Cat struct {
    name string
}

//
// Return a pointer to the supplied struct via interface{}
//
func to_struct_ptr(obj interface{}) interface{} {

    fmt.Println("obj is a", reflect.TypeOf(obj).Name())

    // Create a new instance of the underlying type 
    vp := reflect.New(reflect.TypeOf(obj))

    // Should be a *Cat and Cat respectively
    fmt.Println("vp is", vp.Type(), " to a ", vp.Elem().Type())

    vp.Elem().Set(reflect.ValueOf(obj))

    // NOTE: `vp.Elem().Set(reflect.ValueOf(&obj).Elem())` does not work

    // Return a `Cat` pointer to obj -- i.e. &obj.(*Cat)
    return vp.Interface()
}

//
// Dump out a pointer ...
//
func test_ptr(ptr interface{}) {
    v := reflect.ValueOf(ptr)
    fmt.Println("ptr is a", v.Type(), "to a", reflect.Indirect(v).Type())
}

func main() {
    cat := Cat{name: "Fuzzy Wuzzy"}

    // Reports "*main.Cat"
    test_ptr(&cat)

    // Get a "*Cat" generically via interface{}
    sp := to_struct_ptr(cat)

    // *should* report "*main.Cat" also
    test_ptr(sp)

    fmt.Println("sp is",sp)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM