2016-10-05 135 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

感謝您的詳細解答,包括博客文章。很有幫助。 –