简体   繁体   中英

How to get the pointer to a struct passed through interface{} in golang?

No, I don't think this is a duplicate of How to determine an interface{} value's "real" type? . I know how to get the Type of an interface variable, but I can't find a way to get the pointer to an interface{}'s real type.

Recently, I got into trouble with interface{} . I have a variable with type A been passed through interface{} , a method Tt is defined with *A as the receiver.

I want to call the method Tt but failed because the variable is in an interface{} and I can't get the pointer to the variable.

As you can see, reflect.TypeOf(v) gives the correct type A , but reflect.TypeOf(&v) gives *interface {} instead of *A .

Is there any way to get *A ?

package main

import (
    "fmt"
    "reflect"
)

type SomeStruct1 struct{
}

type SomeStruct2 struct{
}

type SomeStruct3 struct{
}
etc...

func (*SomeStruct1) SomeMethod(){
    fmt.Println("hello")
}
func (*SomeStruct2) SomeMethod(){
    fmt.Println("hello")
}
func (*SomeStruct3) SomeMethod(){
    fmt.Println("hello")
}
etc...

func DoSomething(arg interface{}){
    switch v:=b.(type){
        []byte:{
            dosomething for []byte
        }
        default:{
            var m reflect.Value
            if value.Kind() != reflect.Ptr {
                m = reflect.ValueOf(&v).MethodByName("SomeMethod")
            } else {
                m = reflect.ValueOf(v).MethodByName("SomeMethod")
            }
            m.Call(nil)
        }
}

func main() {
    DoSomething([]byte{...})
    DoSomething(SomeStruct1{})
    DoSomething(&SomeStruct1{})
    etc..
}

Use reflection:

//
// Return a pointer to the supplied struct via interface{}
//
func to_struct_ptr(obj interface{}) interface{} {
    vp := reflect.New(reflect.TypeOf(obj))
    vp.Elem().Set(reflect.ValueOf(obj))
    return vp.Interface()
}

Pass in an interface with T , then you can get an interface with *T

To call the pointer method Tt() , you must have an *A (or take the address of an addressable A value). The A value in variable b is not addressable , and therefore the A pointer methods are not accessible through b .

The fix is to start with the address of a :

var a A
var b interface{}
b = &a // Note change on this line
switch v := b.(type) {
default:
    reflect.ValueOf(v).MethodByName("Tt").Call(nil)
}

In the call reflect.ValueOf(v) , the value in v is passed as the argument. The ValueOf function unpacks the empty interface to recover a value of type A .

In the call reflect.ValueOf(&v) , an *interface{} is stored in the empty interface, which is then passed as the argument. The ValueOf function unpacks the empty interface to recover a value of type *interface{} . This is the address of the variable v , not the address of the variable a .

Reflection is not required in this specific example:

var a A
var b interface{}
b = &a
switch v := b.(type) {
case interface {
    Tt()
}:
    v.Tt()
default:
    fmt.Println("not handled")
}

You need just type cast. Example:

type SomeStruct1 struct{
    someList []string
}

func (s *SomeStruct1) print() {
    fmt.Printf("%v\n", s.someList)
...

func Call(T interface{}){
    switch T.(type){
    case *SomeStruct1:
        t := T.(*SomeStruct1) // cast as pointer to struct
        t.print()
    ...
    }
}

func main() {
    a := SomeStruct{
        someList: []string{"a", "b"}
    }
    Call(&a) // pass a as ptr
}

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