在go(golang)中,如何将接口指针转换为struct指针?

时间:2015-03-23 22:47:03

标签: go

我想使用一些需要指向结构的指针的外部代码。在调用代码时,我有一个接口变量。

当从该变量创建指针时,指针的类型为interface{}*,当我需要它作为结构类型的指针类型时。

图片TestCanGetStructPointer 中的代码不了解Cat类,并且它存在于某个外部包中。

我怎样才能把它投射到这个?

以下是代码示例:

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)
    }

}

测试失败了:

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

3 个答案:

答案 0 :(得分:2)

@ dyoo的示例确实有效,但它依赖于您手动投射DogCat

这里有一个复杂/冗长的例子,它在某种程度上避免了这种限制:

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

答案 1 :(得分:1)

以下内容可能有所帮助: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)
    }
}

答案 2 :(得分:1)

我发现了这个线程: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)
}