首頁 >後端開發 >Golang >Golang中使用JSON時區分空白字段和​​未設定字段的方法

Golang中使用JSON時區分空白字段和​​未設定字段的方法

藏色散人
藏色散人轉載
2020-09-09 09:37:292951瀏覽
##上設定對空格欄位上使用

golang教程欄位給大家介紹Golang中使用JSON時區分空白字段和​​未設定字段的方法lang中使用JSON時區分空字段和未設定的方法如何幫助對未設定字段的朋友!

Golang中使用JSON時區分空白字段和​​未設定字段的方法

幾週前, 我在使用Golang中使用JSON時區分空白字段和​​未設定字段的方法lang 微服務, 需要添加使用JSON 資料的CURP 操作的支援. 通常, 我會為實體創建一個結構體, 該結構體中定義了所有欄位以及'omitempty' 屬性, 如下所示

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

#問題

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

例如, 假設更新請求的JSON 資料看起來像是這樣

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

注意為空的desc 欄位. 現在讓我們來看看這段請求資料在Golang中使用JSON時區分空白字段和​​未設定字段的方法 中解封後是怎麼樣的

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 的現有值, 在這種情況下, 再次發送一個描述字串是不正確的, 因此請求的JSON 資料可能看起來像是這樣

{"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作為空字串獲取, 那麼如何區分未設定字段和空字段

簡答? 指針

解決辦法

受到一些現有Golang中使用JSON時區分空白字段和​​未設定字段的方法lang 庫的啟發, 如

go-github. 我們可以將結構體字段更改為指針類型, 如下所示

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

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

nil).

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

注意 - 我沒有將'Id' 欄位更改為指標類型, 因為它不具備空狀態, id 是必需的, 類似資料庫中的id.

我們再嘗試一下.

func Test_JSON_Empty(t *testing.T) {
   jsonData := `{"id":"1234","name":"xyz","desc":""}`
   req := Article{}
   _ = json.Unmarshal([]byte(jsonData), &req)
   fmt.Printf("%+v\n", req)
   fmt.Printf("%s\n", *req.Name)
   fmt.Printf("%s\n", *req.Desc)
}
func Test_JSON_Nil(t *testing.T) {
   jsonData := `{"id":"1234","name":"xyz"}`
   req := Article{}
   _ = json.Unmarshal([]byte(jsonData), &req)
   fmt.Printf("%+v\n", req)
   fmt.Printf("%s\n", *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 獲得了一個非空指標並包含一個空字串的值. 第二種情況, 該欄位未設定, 我們得到了一個空字符串連指標.

因此我們能夠區分兩種更新. 這種方式不僅適用於字串, 而且適用於其他的所有資料型別, 包括整數型, 巢狀結構體, 等.

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

空安全性: 非指標資料型別具備固有的空安全性. 在Golang中使用JSON時區分空白字段和​​未設定字段的方法lang 中這表示字串或整數永遠不能為空. 他們始終具備預設值. 但是如果定義了指標, 則這些資料類型在未手動設定的情況下預設為空. 因此, 嘗試在不驗證可空性的情況下存取那些指標的資料可能會導致應用程式崩潰.

# 以下代码将崩溃, 因为 desc 为空
func Test_JSON_Nil(t *testing.T) {
   jsonData := `{"id":"1234","name":"xyz"}`
   req := Article{}
   _ = json.Unmarshal([]byte(jsonData), &req)
   fmt.Printf("%+v\n", req)
   fmt.Printf("%s\n", *req.Desc)
}

透過始終檢查空指標可以很容易的解決此問題, 但你的程式碼可能會看起來會很囉嗦.

##可列印性

: 如在基於指標的解決方案的輸出中你可能已經注意到的問題, 不會列印指標的值. 二十列印了指標的十六進位值, 這在應用程式中沒什麼用. 這也可以透過重新使用stringer 介面來克服.

func (a *Article) String() string {
   output:=fmt.Sprintf("Id: %s ",a.Id)
   if a.Name!=nil{
   output+=fmt.Sprintf("Name: &#39;%s&#39; ",*a.Name)
   }
   if u.Desc!=nil{
   output+=fmt.Sprintf("Desc: &#39;%s&#39; ",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

#

以上是Golang中使用JSON時區分空白字段和​​未設定字段的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:learnku.com。如有侵權,請聯絡admin@php.cn刪除