亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長資訊網
    最全最豐富的資訊網站

    Golang中使用JSON時區(qū)分空字段和未設置字段的方法

    下面由golang教程欄目給大家介紹Golang中使用JSON時區(qū)分空字段和未設置字段的方法,希望對需要的朋友有所幫助!

    Golang中使用JSON時區(qū)分空字段和未設置字段的方法

    幾周前, 我在使用 Golang 微服務, 需要添加使用 JSON 數(shù)據(jù)的 CURP 操作的支持. 通常, 我會為實體創(chuàng)建一個結構體, 該結構體中定義了所有字段以及 'omitempty' 屬性, 如下所示

    type Article struct {    Id   string      `json:"id"`    Name string      `json:"name,omitempty"`    Desc string      `json:"desc,omitempty"` }

    問題

    但是這種表示形式帶來了嚴重的問題, 尤其對于 Update 或 Edit 操作而言.

    例如, 假設更新請求的 JSON 數(shù)據(jù)看起來像是這樣

    {"id":"1234","name":"xyz","desc":""}

    注意為空的 desc 字段. 現(xiàn)在讓我們來看看這段請求數(shù)據(jù)在 Go 中解封后是怎么樣的

    func Test_JSON1(t *testing.T) {             jsonData:=`{"id":"1234","name":"xyz","desc":""}`    req:=Article{}    _=json.Unmarshal([]byte(jsonData),&req)    fmt.Printf("%+v",req) }Output: === RUN   Test_JSON1 {Id:1234 Name:xyz Desc:}

    這里的描述是一個空字符串, 很明顯客戶端希望將 desc 設置為空字符串, 這是由我們的程序推斷出來的.

    但是, 如果客戶端不希望更改 Desc 的現(xiàn)有值, 在這種情況下, 再次發(fā)送一個描述字符串是不正確的, 因此請求的 JSON 數(shù)據(jù)可能看起來像是這樣

    {"id":"1234","name":"xyz"}

    我們解封到我們的結構體中

    func Test_JSON2(t *testing.T) {             jsonData:=`{"id":"1234","name":"xyz"}`    req:=Article{}    _=json.Unmarshal([]byte(jsonData),&req)    fmt.Printf("%+v",req) }Output: === RUN   Test_JSON2 {Id:1234 Name:xyz Desc:}

    額, 仍然會將 Desc 作為空字符串獲取, 那么如何區(qū)分未設置字段和空字段

    簡答? 指針

    解決辦法

    受到一些現(xiàn)有 Golang 庫的啟發(fā), 如 go-github. 我們可以將結構體字段更改為指針類型, 如下所示

    type Article struct {    Id    string      `json:"id"`    Name *string      `json:"name,omitempty"`    Desc *string      `json:"desc,omitempty"` }

    通過這樣做, 我們在字段中添加了額外的狀態(tài). 如果原始 JSON 中不存在該字段, 則結構體字段將為空 (nil).

    另一方面, 如果該字段確實存在并且為空, 則指針不為空, 并且該字段包含空值.

    注意 – 我沒有將 'Id' 字段更改為指針類型, 因為它不具備空狀態(tài), id 是必需的, 類似數(shù)據(jù)庫中的 id.

    我們再嘗試一下.

    func Test_JSON_Empty(t *testing.T) {    jsonData := `{"id":"1234","name":"xyz","desc":""}`    req := Article{}    _ = json.Unmarshal([]byte(jsonData), &req)    fmt.Printf("%+vn", req)    fmt.Printf("%sn", *req.Name)    fmt.Printf("%sn", *req.Desc) } func Test_JSON_Nil(t *testing.T) {    jsonData := `{"id":"1234","name":"xyz"}`    req := Article{}    _ = json.Unmarshal([]byte(jsonData), &req)    fmt.Printf("%+vn", req)    fmt.Printf("%sn", *req.Name) }

    Output

    === RUN   Test_JSON_Empty {Id:1234 Name:0xc000088540 Desc:0xc000088550} Name: xyz Desc:  --- PASS: Test_JSON_Empty (0.00s)=== RUN   Test_JSON_Nil {Id:1234 Name:0xc00005c590 Desc:<nil>} Name: xyz --- PASS: Test_JSON_Nil (0.00s)

    第一種情況, 由于 desc 設置為空字符串, 因此我們在 Desc 獲得了一個非空指針并包含一個空字符串的值. 第二種情況, 該字段未設置, 我們得到了一個空字符串指針.

    因此我們能夠區(qū)分兩種更新. 這種方式不僅適用于字符串, 而且適用于其他的所有數(shù)據(jù)類型, 包括整型, 嵌套結構體, 等.

    但是這種方法也存在一些問題.

    空安全性: 非指針數(shù)據(jù)類型具備固有的空安全性. 在 Golang 中這意味著字符串或整型永遠不能為空. 他們始終具備默認值. 但是如果定義了指針, 則這些數(shù)據(jù)類型在未手動設置的情況下默認為空. 因此, 嘗試在不驗證可空性的情況下訪問那些指針的數(shù)據(jù)可能會導致應用程序崩潰.

    # 以下代碼將崩潰, 因為 desc 為空 func Test_JSON_Nil(t *testing.T) {    jsonData := `{"id":"1234","name":"xyz"}`    req := Article{}    _ = json.Unmarshal([]byte(jsonData), &req)    fmt.Printf("%+vn", req)    fmt.Printf("%sn", *req.Desc) }

    通過始終檢查空指針可以很容易的解決此問題, 但你的代碼可能會看起來會很啰嗦.

    可打印性: 如在基于指針的解決方案的輸出中你可能已經注意到的問題, 不會打印指針的值. 二十打印了指針的十六進制值, 這在應用程序中沒什么用. 這也可以通過重新使用 stringer 接口來克服.

    func (a *Article) String() string {    output:=fmt.Sprintf("Id: %s ",a.Id)    if a.Name!=nil{    output+=fmt.Sprintf("Name: '%s' ",*a.Name)    }    if u.Desc!=nil{    output+=fmt.Sprintf("Desc: '%s' ",u.Desc)    }    return output }

    附錄:

    • 解決上述問題的另一種方法是使用具有可為空類型的三方庫, 其類型可提供檢查是否為空的方法, 而無需關心指針.
    • github.com/guregu/null
    • github.com/google/go-github

    原文地址:https://medium.com/@arpitkh96/differentiate-between-empty-and-not-set-fields-with-json-in-golang-957bb2c5c065

    譯文地址:https://learnku.com/go/t/49332

    贊(0)
    分享到: 更多 (0)
    網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號