5

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..
}
user1895011
  • 61
  • 1
  • 3

3 Answers3

7

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

shawn
  • 4,305
  • 1
  • 17
  • 25
3

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")
}
Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
0

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
}
user11
  • 1