Golang 的 “omitempty” 關(guān)鍵字略解

json和struct轉(zhuǎn)換簡單介紹

熟悉 Golang 的朋友對于 json 和 struct 之間的轉(zhuǎn)換一定不陌生,為了將代碼中的結(jié)構(gòu)體與 json 數(shù)據(jù)解耦,通常我們會(huì)在結(jié)構(gòu)體的 field 類型后加上解釋說明,注意:結(jié)構(gòu)體的屬性首字母必須大寫,否則json解析會(huì)不生效

type Person struct {
    Name string `json:"json_key_name"`
    Age  int    `json:"json_key_age"`
}

func main() {

    Per := Person{
        Name: "小飯",
        Age:  18,
    }
    
    res, _ := json.Marshal(Per)
    fmt.Println(string(res))
    return
}  
//輸出結(jié)果
{"json_key_name":"小飯","json_key_age":18}

結(jié)構(gòu)體只初始化部分變量

接下來我們看另外一種情況

    p := Person{
        Name: "小飯",
    }
    res, _ := json.Marshal(p)
    fmt.Println(string(res))

如果我們在結(jié)構(gòu)體初始化的時(shí)候只初始化了其中一個(gè)字段Name,那么理論上來說返回的json應(yīng)該是

{"Name":"小飯"}

但是我們實(shí)際運(yùn)行一下返回的結(jié)果卻是

{"Name":"小飯","Age":0}

這明顯是不符合我們的預(yù)期的,因?yàn)锳ge字段是我們不需要的。

如何解決

接下來就輪到咱們今天的主角登場了,解決方式很簡單,在后面加上omitempty即可

type Person struct {
    Name string
    Age  int `json:",omitempty"`
}
func main() {
    p := Person{
        Name: "小飯",
    }
    res, _ := json.Marshal(p)
    fmt.Println(string(res))
}
//輸出結(jié)果
{"Name":"小飯"}

結(jié)構(gòu)體的特殊情況

我們再來看下面的這個(gè)例子

type Person struct {
    Name string
    Age  int
}

type Student struct {
    Num    int
    Person Person `json:",omitempty"`  //對結(jié)構(gòu)體person使用了omitempty
}

func main() {
    Stu := Student{
        Num: 5,
    }
    res, _ := json.Marshal(Stu)
    fmt.Println(string(res))
}  

我們對結(jié)構(gòu)體Person定義了omitempty,按理說我們在初始化的時(shí)候并沒有初始化結(jié)構(gòu)體的任何屬性,所以轉(zhuǎn)換成json之后的打印結(jié)果應(yīng)該是只有{"Num":5}的,但是我們實(shí)際運(yùn)行之后發(fā)現(xiàn)打印的結(jié)果卻是

{"Num":5,"Person":{"Name":"","Age":0}}

為什么omitempty對于結(jié)構(gòu)體類型不生效了呢?這是因?yàn)榻Y(jié)構(gòu)體(上面例子的Person)不知道空值是什么,GO只知道簡單結(jié)構(gòu)體例如int,string,pointer 這種類型的空值,為了不顯示我們沒有提供值的自定義結(jié)構(gòu)體,我們可以使用結(jié)構(gòu)體指針

為什么用指針類型就可以解決這個(gè)問題?因?yàn)?strong>指針是基本類型,Golang知道他的空值是啥,所以就直接賦值為nil(指針類型的空值)。

type Person struct {
    Name string
    Age  int
}

type Student struct {
    Num    int
    Person *Person `json:",omitempty"`  //如果想要omitempty生效,必須是指針類型
}

func main() {
    Stu := Student{
        Num: 5,
    }
    res, _ := json.Marshal(Stu)
    fmt.Println(string(res))
}  
//輸出結(jié)果
{"Num":5}

omitempty的一個(gè)大坑

我們接下來還是看例子

type Person struct {
    Age int `json:",omitempty"`
}
func main() {
    Per := Person{
        Age: 0,
    }
    res, _ := json.Marshal(Per)
    fmt.Println(string(res))
}  

按照咱們的預(yù)期,應(yīng)該給輸出

{"Age":0}

對不對,但是咱們實(shí)際運(yùn)行以后輸出的卻是

{}

這明顯有問題啊,咱們需要的是輸出的json字段,是必須有age,而且值是0,現(xiàn)在什么都沒輸出明顯是有問題的。因?yàn)镚olang把0當(dāng)成了零值,所以跟沒有賦值是一樣的
如果想解決這種問題一種方法是使用int指針,因?yàn)閕nt指針的空值為nil,當(dāng)我想輸出0的時(shí)候,我傳進(jìn)去地址,地址肯定不是空值nil,這樣肯定會(huì)顯示出來0

type Person struct {
    Age *int `json:",omitempty"`
}

func main() {
    age := 0
    Per := Person{
        Age: &age,
    }
    res, _ := json.Marshal(Per)
    fmt.Println(string(res))
}  

總結(jié)

  • omitempty只是在把結(jié)構(gòu)體轉(zhuǎn)換成json的過程中,只會(huì)影響json轉(zhuǎn)換后的結(jié)果,并不是影響結(jié)構(gòu)體本身,所以結(jié)構(gòu)體的任何屬性設(shè)置了omitempty之后,都不影響其正常使用
  • omitempty的作用簡單來說就是在結(jié)構(gòu)體轉(zhuǎn)換json的過程中,把沒有賦值的結(jié)構(gòu)體屬性不在json中輸出而已
  • omitempty只支持簡單的數(shù)據(jù)類型,對結(jié)構(gòu)體的數(shù)據(jù)類型是不生效的,如果需要生效,只能用結(jié)構(gòu)體指針
  • omitempty分不清楚0值,""值和未賦值如果給某個(gè)屬性賦值0或者"",并且想輸出,只能用指針類型

本文由mdnice多平臺發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容