如何在golang中获取通过接口{}传递的结构的指针?

时间:2017-10-08 14:50:57

标签: pointers go interface

  

不,我不认为这是重复的    How to determine an interface{} value's "real" type?。我知道如何获取接口变量的类型,但是我无法找到一种方法来获取指向接口{}的真实类型的指针。

最近,我遇到了interface{}的问题。我有一个类型为A的变量已通过interface{}传递,方法Tt定义为* A作为接收方。

我想调用方法Tt但是失败了,因为变量在interface{}中,我无法获得指向变量的指针。

如您所见,reflect.TypeOf(v)提供了正确的类型A,但reflect.TypeOf(&v)提供了*interface {}而不是*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..
}

3 个答案:

答案 0 :(得分:3)

使用反射:

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

通过interface传递T,然后通过interface获得*T

答案 1 :(得分:1)

要调用指针方法*A,您必须拥有A(或获取addressable A值的地址。变量b中的A值不是addressable,因此无法通过b访问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) }

的地址开始
reflect.ValueOf(v)

在调用v中,ValueOf中的值作为参数传递。 A函数解包空接口以恢复类型reflect.ValueOf(&v)的值。

在调用*interface{}中,ValueOf存储在空接口中,然后作为参数传递。 *interface{}函数解包空接口以恢复类型v的值。这是变量a的地址,而不是变量var a A var b interface{} b = &a switch v := b.(type) { case interface { Tt() }: v.Tt() default: fmt.Println("not handled") } 的地址。

此特定示例中不需要反射:

       // establish a connection
        $db     = Database::getInstance();
        $mysqli = $db->getConnection();

        // run sql
        $sql = "SELECT * FROM `solutions` WHERE 1 LIMIT 6";
        // run query
        $result = $mysqli->query($sql);

        // echo '<pre>'.var_export($result, TRUE).'</pre>';

        // check query
        if($result){
            // echo '<pre>'.var_export($row, TRUE).'</pre>';
            while($row = $result->fetch_assoc()){
                echo '
                <span class="solution">
                    // this section floats right
    <div style="background-image:url('.$row['img_thumbnails'].'); " class="solution-img"></div><a href="solutions.php?key='.$row['solution_key'].'"><h2>'.$row['name'].'</h2></a>
                        <p>'.$row['headline_title_hook'].'</p>
                        </span>';
            }

        }else{
            trigger_error('SQL has an error');
        }

答案 2 :(得分:0)

你只需要输入。 例如:

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
}
相关问题