1 回答

TA貢獻1911條經驗 獲得超7個贊
代碼中存在幾個錯誤。
首先,如果傳遞的值是指針,則只需調用 Value.Elem()
。當你迭代這些字段并找到一個結構類型的字段,并且你用它遞歸地調用它時,那將不是一個指針,因此你不能調用它。ReadStruct()
Elem()
所以這樣做是這樣的:
val := reflect.ValueOf(st)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
接下來,既然你從調用反射開始。ValueOf(),
即假定您必須將非反射值傳遞給(即,不是反射類型的值)。值
)。ReadStruct()
ReadStruct()
但是,當您迭代字段并調用 Value.Field()
時,您將獲得一個包裝字段。您必須調用 Value.Interface()
來提取非反射值,以便在遞歸調用中傳遞。reflect.Value
要循環訪問切片,只需使用值.Len()
獲取切片長度,并使用 Value.Index()
獲取切片的第 i 個元素。
以下是遍歷函數的更正版本:
// I used this type as you didn't post it in your question.
type Info struct {
Key, Value string
}
func ReadStruct(st interface{}) {
val := reflect.ValueOf(st)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
// fmt.Println(val.Type().Field(i).Type.Kind())
f := val.Field(i)
switch f.Kind() {
case reflect.Struct:
ReadStruct(f.Interface())
case reflect.Slice:
for j := 0; j < f.Len(); j++ {
ReadStruct(f.Index(i).Interface())
}
case reflect.String:
fmt.Printf("%v=%v\n", val.Type().Field(i).Name, val.Field(i).Interface())
}
}
}
測試它:
c := &Container{
Name: "c1",
Items: []Item{
{
Name: "i1",
Info: Info{Key: "k1", Value: "v1"},
},
{
Name: "i2",
Info: Info{Key: "k2", Value: "v2"},
},
},
}
ReadStruct(c)
輸出(在Go游樂場上嘗試):
Name=c1
Name=i2
Key=k2
Value=v2
Name=i2
Key=k2
Value=v2
注意:通過使用遞歸調用,可以提取和重新獲取值。始終使用 s 會更有效,因此您可以避免這些不必要的調用。reflect.Valuereflect.Value
這是你如何做到這一點:
func ReadStruct(st interface{}) {
readStruct(reflect.ValueOf(st))
}
func readStruct(val reflect.Value) {
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
// fmt.Println(val.Type().Field(i).Type.Kind())
f := val.Field(i)
switch f.Kind() {
case reflect.Struct:
readStruct(f)
case reflect.Slice:
for j := 0; j < f.Len(); j++ {
readStruct(f.Index(i))
}
case reflect.String:
fmt.Printf("%v=%v\n", val.Type().Field(i).Name, val.Field(i))
}
}
}
這將輸出相同的結果。在Go游樂場上試試這個。
- 1 回答
- 0 關注
- 104 瀏覽
添加回答
舉報