2016-10-05 130 views
4

如何知道我可以从reply对象/接口访问的字段?我尝试了反思,但似乎你必须先知道字段名称。如果我需要知道所有可用的字段,该怎么办?从接口获取所有字段

// Do sends a command to the server and returns the received reply. 
Do(commandName string, args ...interface{}) (reply interface{}, err error) 

回答

13

可以使用reflect.TypeOf()函数来获得一个reflect.Type类型描述符。从那里,您可以列出存储在界面中的动态值的字段。

实施例:

type Point struct { 
    X int 
    Y int 
} 

var reply interface{} = Point{1, 2} 
t := reflect.TypeOf(reply) 
for i := 0; i < t.NumField(); i++ { 
    fmt.Printf("%+v\n", t.Field(i)) 
} 

输出:

{Name:X PkgPath: Type:int Tag: Offset:0 Index:[0] Anonymous:false} 
{Name:Y PkgPath: Type:int Tag: Offset:4 Index:[1] Anonymous:false} 

一个Type.Field()调用的结果是一个reflect.StructField值,它是一个struct,含有除其他事项外的字段的名称:

type StructField struct { 
    // Name is the field name. 
    Name string 
    // ... 
} 

如果你还想要的值字段,你可以使用reflect.ValueOf()获得reflect.Value(),然后你可以使用Value.Field()Value.FieldByName()

v := reflect.ValueOf(reply) 
for i := 0; i < v.NumField(); i++ { 
    fmt.Println(v.Field(i)) 
} 

输出:

1 
2 

尝试它的Go Playground

注意:通常指向结构的指针被封装在一个接口中。在这种情况下,你可以使用Type.Elem()Value.Elem()为“导航”的尖型或价值:

t := reflect.TypeOf(reply).Elem() 

v := reflect.ValueOf(reply).Elem() 

如果您不知道它是否是一个指针或没有,你可以用Type.Kind()Value.Kind()检查,比较与reflect.Ptr结果:

t := reflect.TypeOf(reply) 
if t.Kind() == reflect.Ptr { 
    t = t.Elem() 
} 

// ... 

v := reflect.ValueOf(reply) 
if v.Kind() == reflect.Ptr { 
    v = v.Elem() 
} 

尝试在Go Playground这个变体。

想要详细了解Go的反思,请阅读博文:The Laws of Reflection

+1

准确地说,我希望得到回答!感谢您为此付出额外努力并提供有效的代码。 – RAFJR

+1

感谢您的详细解答,包括博客文章。很有帮助。 –