Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Gunakan pantulan untuk mengulang struktur secara rekursif dan tetapkan medan

Gunakan pantulan untuk mengulang struktur secara rekursif dan tetapkan medan

WBOY
WBOYke hadapan
2024-02-10 20:45:10585semak imbas

Gunakan pantulan untuk mengulang struktur secara rekursif dan tetapkan medan

Dalam artikel ini, editor PHP Xigua akan memperkenalkan cara menggunakan refleksi untuk mengulang struktur secara rekursif dan menetapkan medan. Refleksi ialah ciri berkuasa dalam PHP yang membolehkan kami memperoleh dan memanipulasi maklumat seperti kelas, kaedah, sifat, dll. pada masa jalan. Struktur lelaran rekursif ialah kaedah pemprosesan biasa, yang boleh membantu kami merentasi dan mengendalikan struktur data yang kompleks. Dengan menggabungkan pantulan dan struktur lelaran rekursif, kita boleh mendapatkan dan menetapkan nilai medan dengan mudah, membolehkan pengaturcaraan yang lebih fleksibel dan cekap. Dalam kandungan berikut, kami akan memperkenalkan proses ini secara terperinci untuk membantu pembaca memahami dan menggunakan teknik ini dengan lebih baik.

Kandungan soalan

Saya ingin membina program yang menggunakan refleksi untuk menetapkan medan struktur. Saya membuatnya berfungsi untuk medan peringkat atas, tetapi saya bergelut dengan medan struct bersarang. Bagaimana untuk mengulangi medan struct bersarang?

type Payload struct {
    Type    string   `json:"type"`
    SubItem *SubItem `json:"sub_item"`
}

type SubItem struct {
    Foo string `json:"foo"`
}

func main() {
    var payload Payload
    setValue(&payload, "type", "test1")
    setValue(&payload, "sub_item.foo", "test2")
}

func setValue(structPtr interface{}, key string, value string) {
    structValue := reflect.Indirect(reflect.ValueOf(structPtr))
    for i, subkey := range strings.Split(key, ".") {
        isLast := i == len(strings.Split(key, "."))-1
        var found bool
        // this line is crashing with "reflect: call of reflect.Value.NumField on zero Value"
        for i := 0; i < structValue.NumField(); i++ {
            field := structValue.Type().Field(i)
            jsonTags := strings.Split(field.Tag.Get("json"), ",")
            if jsonTags[0] == subkey {
                found = true
                if isLast {
                    if isLast {
                        // last element
                        // TODO set value
                        fmt.Printf("TODO set value %s to %v", value, structValue)
                        structValue = reflect.Indirect(reflect.ValueOf(structPtr))
                    }
                } else {
                    structValue = reflect.Indirect(reflect.ValueOf(structValue.Field(i).Interface()))
                }
                break
            }
        }
        if !found {
            panic(fmt.Errorf("failed to find field %s", key))
        }
    }
}

Penyelesaian

Gunakan ciri ini:

func setvalue(p interface{}, key string, value interface{}) {
    v := reflect.valueof(p)

    // loop through the names in key to find the target field.
    for _, name := range strings.split(key, ".") {

        // if the value is pointer, then
        // - allocate value if ptr is nil.
        // - indirect ptr
        for v.kind() == reflect.ptr {
            if v.isnil() {
                v.set(reflect.new(v.type().elem()))
            }
            v = v.elem()
        }

        // we expect that the value is struct. find the 
        // named field.
        v = findjsonfield(v, name)
        if !v.isvalid() {
            panic(fmt.sprintf("could not find field %s", key))
        }
    }
    
    // set the field.
    v.set(reflect.valueof(value))
}

Fungsi findjsonfield mencari medan struktur melalui tag json medan:

func findJSONField(v reflect.Value, name string) reflect.Value {
    t := v.Type()
    for i := 0; i < v.NumField(); i++ {
        if tag, _, _ := strings.Cut(t.Field(i).Tag.Get("json"), ","); tag == name {
            return v.Field(i)
        }
    }
    return reflect.Value{}
}

https://www.php.cn/link/e4848ea6b69df2c66c87e2877e74726b

Atas ialah kandungan terperinci Gunakan pantulan untuk mengulang struktur secara rekursif dan tetapkan medan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam