Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Buat objek json secara manual dari struct dalam golang

Buat objek json secara manual dari struct dalam golang

WBOY
WBOYke hadapan
2024-02-12 11:03:081066semak imbas

Buat objek json secara manual dari struct dalam golang

Dalam golang, mencipta objek json secara manual daripada struct ialah operasi biasa. Dengan menukar struct kepada format json, kami boleh menggunakannya dengan mudah dalam penghantaran atau storan rangkaian. Dalam artikel ini, editor PHP Banana akan memperkenalkan anda cara menggunakan pakej terbina dalam golang untuk mencapai fungsi ini. Bukan itu sahaja, kami juga akan meneroka cara menangani medan bersarang dalam struct dan cara menangani jenis medan khas. Sama ada anda seorang pemula atau pembangun yang berpengalaman, artikel ini akan memberikan anda panduan terperinci untuk membantu anda membuat objek json dengan mudah dalam golang. Mari mulakan!

Kandungan soalan

Saya ada struktur untuk katakan

<code>type Foo struct {
  A string `json:",omitemtpy"
}
</code>

Saya tahu saya boleh menukarnya dengan mudah kepada json menggunakan sesuatu seperti ini

json.Marshal(Foo{})

Ia akan mengembalikan rentetan json kosong.

Tetapi saya perlu menggunakan struktur yang sama untuk mengembalikan perwakilan json struktur dengan semua medan dan "nilai nol" yang terdapat dalam json. (Sebenarnya, ia adalah struktur yang sangat besar, jadi saya tidak boleh menyimpan salinan tanpa tag)

Apakah cara paling mudah?

Pada asasnya, saya perlu mencipta json marshal bagi struktur yang mengabaikan tag omitempty json.

Penciptaan json ini tidak perlu cekap atau berprestasi.

Saya lebih suka perpustakaan untuk tugasan seperti ini, tetapi kebanyakan perpustakaan yang saya lihat sama ada mencipta beberapa format khas atau menghormati pengabaian

Editor:

Pilih https://stackoverflow.com/a/77799949/2187510 sebagai jawapan saya dan lakukan beberapa kerja tambahan untuk membenarkan nilai lalai (menggunakan kodnya untuk rujukan)

defaultFoo := FoodWithPts{ Str: "helloWorld"}
dupFooType := dupType(reflect.TypeOf(defaultFoo))
foo := reflect.Zero(dupFooType).Interface()

// New additions
defaults, _ := json.Marshal(defaultFoo)
json.Unmarshal(defaults, &foo)   // overwrites foo with defaults
// End New additions

data, err := json.Marshal(foo)
fmt.Println("dup FooWithPtrs:\n", string(data), err)

Keluaran:

dup FooWithPtrs:
    {"String":"helloWorld","Int":0,"Bar":null} <nil>

Penyelesaian

Anda tidak boleh mengubah suai label pada masa jalan, tetapi anda boleh mencipta jenis struct pada masa jalan menggunakan $$c$$reflect.StructOf().

Jadi ideanya adalah untuk menyalin jenis struct tetapi mengecualikan pilihan ,omitempty<code>,omitempty daripada tag JSON dalam pendua.

Anda boleh menemui semua contoh di bawah di Go Playground.

Ia lebih mudah daripada yang orang fikirkan pada mulanya. Kita hanya perlu melakukannya secara rekursif (satu medan struct mungkin satu lagi struct), dan kita pasti perlu berurusan dengan petunjuk:

func dupType(t reflect.Type) reflect.Type {
    if t.Kind() == reflect.Pointer {
        return reflect.PointerTo(dupType(t.Elem()))
    }

    if t.Kind() != reflect.Struct {
        return t
    }

    var fields []reflect.StructField

    for i := 0; i < t.NumField(); i++ {
        sf := t.Field(i)
        sf.Type = dupType(sf.Type)
        // Keep json tag but cut ,omitempty option if exists:
        if tag, _ := strings.CutSuffix(sf.Tag.Get("json"), ",omitempty"); tag == "" {
            sf.Tag = ""
        } else {
            sf.Tag = `json:"` + reflect.StructTag(tag) + `"`
        }
        fields = append(fields, sf)
    }

    return reflect.StructOf(fields)
}

Mari kita uji dengan jenis ini:

type Foo struct {
    Str string `json:"String,omitempty"`
    Int int    `json:",omitempty"`
    Bar struct {
        Float  float64 `json:",omitempty"`
        PtrInt int     `json:",omitempty"`
        Baz    struct {
            X int `json:"XXXX,omitempty"`
        } `json:",omitempty"`
    } `json:",omitempty"`
}

Pertama, berikut ialah output JSON tanpa pertindihan jenis:

data, err := json.Marshal(Foo{})
fmt.Println("Foo:\n", string(data), err)

Keluaran:

Foo:
 {"Bar":{"Baz":{}}} <nil>

Perhatikan bahawa kami mendapat medan Bar<code>BarBaz dan Baz

kerana ia adalah struct.

Jom cuba taip copy:

dupFooType := dupType(reflect.TypeOf(Foo{}))
foo := reflect.Zero(dupFooType).Interface()

data, err := json.Marshal(foo)
fmt.Println("dup Foo:\n", string(data), err)

Ini akan menghasilkan:

dup Foo:
 {"String":"","Int":0,"Bar":{"Float":0,"PtrInt":0,"Baz":{"XXXX":0}}} <nil>

Tidak teruk! Apa yang kami mahukan!

Tetapi kami belum selesai. Bagaimana jika kita mempunyai jenis dengan medan penunjuk struktur? Seperti ini:

type FooWithPtrs struct {
    Str string `json:"String,omitempty"`
    Int int    `json:",omitempty"`
    Bar *struct {
        Float  float64 `json:",omitempty"`
        PtrInt int     `json:",omitempty"`
        Baz    *struct {
            X int `json:"XXXX,omitempty"`
        } `json:",omitempty"`
    } `json:",omitempty"`
}

Cuba JSON menyusun nilai jenis berulang:

dupFooType := dupType(reflect.TypeOf(FooWithPtrs{}))
foo := reflect.Zero(dupFooType).Interface()

data, err := json.Marshal(foo)
fmt.Println("dup FooWithPtrs:\n", string(data), err)

Keluaran:

dup FooWithPtrs:
 {"String":"","Int":0,"Bar":null} <nil>
null,但我们也希望它们的字段也出现在输出中。这需要将它们初始化为非 nilJika struct mengandungi penunjuk, penunjuk ini muncul sebagai null dalam output JSON

, tetapi kami mahu medan mereka muncul dalam output juga. Ini memerlukan permulaannya kepada nilai bukannihil

agar mereka menghasilkan output.

Nasib baik, kita juga boleh menggunakan refleksi untuk melakukan ini:

func initPtrs(v reflect.Value) {
    if !v.CanAddr() {
        return
    }

    if v.Kind() == reflect.Pointer {
        v.Set(reflect.New(v.Type().Elem()))
        v = v.Elem()
    }

    if v.Kind() == reflect.Struct {
        for i := 0; i < v.NumField(); i++ {
            initPtrs(v.Field(i))
        }
    }
}

Kami teruja! Mari lihat dalam tindakan:

dupFooType := dupType(reflect.TypeOf(FooWithPtrs{}))
fooVal := reflect.New(dupFooType)
initPtrs(fooVal.Elem())

data, err := json.Marshal(fooVal.Interface())
fmt.Println("dup and inited FooWithPtrs:\n", string(data), err)

Keluaran:

dup and inited FooWithPtrs:
 {"String":"","Int":0,"Bar":{"Float":0,"PtrInt":0,"Baz":{"XXXX":0}}} <nil>
🎜Tidak teruk! Ia mengandungi semua bidang! 🎜

Atas ialah kandungan terperinci Buat objek json secara manual dari struct dalam golang. 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