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

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

使用反射讀取嵌套結構

使用反射讀取嵌套結構

Go
揚帆大魚 2022-09-12 20:09:03
我編寫了一個遞歸函數,該函數迭代深度嵌套結構,如下所示: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 回答

?
Smart貓小萌

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游樂場上試試這個。


查看完整回答
反對 回復 2022-09-12
  • 1 回答
  • 0 關注
  • 104 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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