次のコラム golang チュートリアル では、Golang で JSON を使用するときに空のフィールドと未設定のフィールドを区別する方法lang で空のフィールドと未設定のフィールドを区別するために JSON 時間を使用する方法を紹介します。必要としている!
数週間前、私は Golang で JSON を使用するときに空のフィールドと未設定のフィールドを区別する方法lang マイクロサービスに取り組んでおり、JSON データを使用した CURP 操作のサポートを追加する必要がありました。通常は、エンティティの構造体を作成していました。以下に示すように、すべてのフィールドと 'omitempty' 属性が本文で定義されています
type Article struct { Id string `json:"id"` Name string `json:"name,omitempty"` Desc string `json:"desc,omitempty"` }
問題
しかし、この表現は、特に更新または編集操作の場合に深刻な問題を引き起こします。 .
たとえば、更新リクエストの 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 は空の文字列として取得されるため、未設定のフィールドと空のフィールドを区別する方法
短い答え? ヒント
解決策
go-github などの既存の Golang で JSON を使用するときに空のフィールドと未設定のフィールドを区別する方法lang ライブラリからインスピレーションを得たもの。以下に示すように、構造体フィールドをポインタ型に変更できます
type Article struct { Id string `json:"id"` Name *string `json:"name,omitempty"` Desc *string `json:"desc,omitempty"` }
これにより、追加のステータスが追加されます。フィールドが元の JSON に存在しない場合、構造体フィールドは空になります (#) ##nil).
一方、フィールドが存在し、null の場合、ポインタは null ではなく、フィールドには null 値が含まれます。Note - '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) }出力
=== 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 が空の文字列に設定されているため、# に null 以外のポインタが返されます。 ##Descには、空の文字列の値が含まれています。2 番目のケースでは、フィールドが設定されておらず、null 文字の String ポインターを取得します。
したがって、2 つのタイプを区別できます。この方法は文字列だけでなく、整数、ネストされた構造などを含む他のすべてのデータ型にも適用されます。
しかし、このアプローチにはいくつかの問題もあります。
##Null 安全性
: 非ポインタ データ型には固有の null 安全性があります。Golang で JSON を使用するときに空のフィールドと未設定のフィールドを区別する方法lang では、これは文字列または整数が決して null にならないことを意味します。これらには常にデフォルト値があります。ただし、ポインタが定義されている場合、これらのデータ型は、次の場合を除き、デフォルトで null になります。したがって、Null 可能性データを検証せずにこれらのポインターにアクセスしようとすると、アプリケーションがクラッシュする可能性があります。# 以下代码将崩溃, 因为 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) }この問題は、Null ポインターを常にチェックすることで簡単に解決できますが、コードが冗長に見える可能性があります。
Yes Printability
: ポインターベースのソリューションの出力でお気づきかと思いますが、ポインターの値は印刷されません。Twenty はポインターの 16 進値を印刷します。アプリケーションではほとんど使用されません。これは、ストリンガー インターフェイスを再利用することで解決することもできます。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 }付録:
上記の問題を解決する別の方法nullable を使用することです。ポインタを気にせずに空かどうかをチェックするメソッドを提供できる型のサードパーティ ライブラリです。
翻訳アドレス: https://learnku.com/go/t/49332
以上がGolang で JSON を使用するときに空のフィールドと未設定のフィールドを区別する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。