简体   繁体   English

如何获取指向通过golang中的interface {}传递的结构的指针?

[英]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? 不,我不认为这与如何确定interface {}值的“真实”类型重复吗? . 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{} . 最近,我遇到了interface{}麻烦。 I have a variable with type A been passed through interface{} , a method Tt is defined with *A as the receiver. 我有一个类型A的变量通过interface{}传递,方法Tt定义为* A作为接收者。

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. 我想调用方法Tt但失败了,因为该变量在interface{}并且我无法获得指向该变量的指针。

As you can see, reflect.TypeOf(v) gives the correct type A , but reflect.TypeOf(&v) gives *interface {} instead of *A . 如您所见, reflect.TypeOf(v)给出正确的类型A ,但是reflect.TypeOf(&v)给出*interface {}而不是*A

Is there any way to get *A ? 有什么办法可以得到*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 传入Tinterface ,然后可以得到*Tinterface

To call the pointer method Tt() , you must have an *A (or take the address of an addressable A value). 要调用指针方法Tt() ,您必须具有*A (或采用可寻址 A值的地址)。 The A value in variable b is not addressable , and therefore the A pointer methods are not accessible through b . 变量bA值不可寻址 ,因此无法通过b访问A指针方法。

The fix is to start with the address of a : 解决方法是从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. 在呼叫reflect.ValueOf(v)在值v被作为参数传递。 The ValueOf function unpacks the empty interface to recover a value of type A . ValueOf函数将空接口ValueOf以恢复类型A的值。

In the call reflect.ValueOf(&v) , an *interface{} is stored in the empty interface, which is then passed as the argument. 在调用reflect.ValueOf(&v)*interface{}存储在空接口中,然后将其作为参数传递。 The ValueOf function unpacks the empty interface to recover a value of type *interface{} . ValueOf函数将空接口ValueOf以恢复*interface{}类型的值。 This is the address of the variable v , not the address of the variable a . 这是变量v的地址,而不是变量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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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