亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用反射讀取嵌套結構

使用反射讀取嵌套結構

Go
拉莫斯之舞 2023-03-07 10:57:28
我編寫了一個遞歸函數來迭代深層嵌套結構,如下所示:type Container struct {    Name string    Items []Item}type Item struct {    Name string    Info Info    Vals []string}// recursively reads nested struct, prints string valuesfunc ReadStruct(st interface{}) {    val := reflect.ValueOf(st).Elem()    for i := 0; i < val.NumField(); i++ {        fmt.Println(val.Type().Field(i).Type.Kind())        switch val.Type().Field(i).Type.Kind() {        case reflect.Struct:            ReadStruct(val.Field(i)) // panic: call of reflect.Value.Elem on struct Value        case reflect.Slice:            // How to iterate over the reflect.Slice?         case reflect.String:            fmt.Printf("%v=%v", val.Type().Field(i).Name, val.Field(i))        }    }  如何訪問內部對象(切片、結構)以使用反射與它們一起工作?遍歷我嘗試使用的切片:for i:= 0; i < val.Field(i).Slice(0, val.Field(i).Len()); i++ { //error: reflect.Value doesnt support indexing//some work} 
查看完整描述

1 回答

?
蝴蝶刀刀

TA貢獻1801條經驗 獲得超8個贊

您的代碼中有幾個錯誤。

Value.Elem()首先,只有在傳遞的值是指針時才需要調用。當您遍歷這些字段并找到一個結構類型的字段時,您遞歸地調用ReadStruct()它,它不會是一個指針,因此您不能調用Elem()它。

所以這樣做:

val := reflect.ValueOf(st)
    if val.Kind() == reflect.Ptr {
    val = val.Elem()
}

接下來,由于您首先ReadStruct()調用reflect.ValueOf(),因此假設您必須將非反射值傳遞給ReadStruct()(即,不是 type 的值reflect.Value)。

但是當您遍歷這些字段時,調用Value.Field(),您會得到一個reflect.Value包裝字段。您必須調用Value.Interface()以從中提取非反射值,以便在遞歸調用中傳遞。

要迭代切片,只需使用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 Playground上嘗試):


Name=c1

Name=i2

Key=k2

Value=v2

Name=i2

Key=k2

Value=v2

注意:通過使用遞歸調用,您正在提取和重新獲取reflect.Value值。始終使用reflect.Values 會更有效率,因此您可以避免這些不必要的調用。


你可以這樣做:


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 Playground試試這個。



查看完整回答
反對 回復 2023-03-07
  • 1 回答
  • 0 關注
  • 108 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號