Buat objek json secara manual dari struct dalam golang

WBOY
Lepaskan: 2024-02-12 11:03:08
ke hadapan
1066 orang telah melayarinya

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>
Salin selepas log masuk

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

json.Marshal(Foo{})
Salin selepas log masuk

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)
Salin selepas log masuk

Keluaran:

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

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)
}
Salin selepas log masuk

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"`
}
Salin selepas log masuk

Pertama, berikut ialah output JSON tanpa pertindihan jenis:

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

Keluaran:

Foo:
 {"Bar":{"Baz":{}}} <nil>
Salin selepas log masuk

Perhatikan bahawa kami mendapat medan Bar<code>BarBaz dan Baz</p> kerana ia adalah struct. <p> </p>Jom cuba taip copy: <p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dupFooType := dupType(reflect.TypeOf(Foo{})) foo := reflect.Zero(dupFooType).Interface() data, err := json.Marshal(foo) fmt.Println(&quot;dup Foo:\n&quot;, string(data), err)</pre><div class="contentsignin">Salin selepas log masuk</div></div> </p>Ini akan menghasilkan: <p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dup Foo: {&quot;String&quot;:&quot;&quot;,&quot;Int&quot;:0,&quot;Bar&quot;:{&quot;Float&quot;:0,&quot;PtrInt&quot;:0,&quot;Baz&quot;:{&quot;XXXX&quot;:0}}} &lt;nil&gt;</pre><div class="contentsignin">Salin selepas log masuk</div></div> </p>Tidak teruk! Apa yang kami mahukan! <p> </p>Tetapi kami belum selesai. Bagaimana jika kita mempunyai jenis dengan medan penunjuk struktur? Seperti ini: <p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">type FooWithPtrs struct { Str string `json:&quot;String,omitempty&quot;` Int int `json:&quot;,omitempty&quot;` Bar *struct { Float float64 `json:&quot;,omitempty&quot;` PtrInt int `json:&quot;,omitempty&quot;` Baz *struct { X int `json:&quot;XXXX,omitempty&quot;` } `json:&quot;,omitempty&quot;` } `json:&quot;,omitempty&quot;` }</pre><div class="contentsignin">Salin selepas log masuk</div></div> </p>Cuba JSON menyusun nilai jenis berulang: <p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dupFooType := dupType(reflect.TypeOf(FooWithPtrs{})) foo := reflect.Zero(dupFooType).Interface() data, err := json.Marshal(foo) fmt.Println(&quot;dup FooWithPtrs:\n&quot;, string(data), err)</pre><div class="contentsignin">Salin selepas log masuk</div></div> </p>Keluaran: <p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dup FooWithPtrs: {&quot;String&quot;:&quot;&quot;,&quot;Int&quot;:0,&quot;Bar&quot;:null} &lt;nil&gt;</pre><div class="contentsignin">Salin selepas log masuk</div></div> <code>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))
        }
    }
}
Salin selepas log masuk

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)
Salin selepas log masuk

Keluaran:

dup and inited FooWithPtrs:
 {"String":"","Int":0,"Bar":{"Float":0,"PtrInt":0,"Baz":{"XXXX":0}}} <nil>
Salin selepas log masuk
🎜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!

Label berkaitan:
sumber:stackoverflow.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!