gopherize.meの画像に基づく
Goコードからは、さまざまなHTTP APIを操作するか、自分でHTTPサービスとして機能する必要があります。
最も一般的なケースの1つは、データベースから構造の形式でデータを受信し、その構造を外部APIに送信し、それに応じて別の構造を受信し、何らかの方法で変換してデータベースに保存することです。
言い換えると、このような処理では、要求構造と応答構造を使用した多くの個別の操作は必要ありません。
APIの要求構造と応答構造には、nilであり、nil以外の値をとることができるフィールドがあるのが普通です。そのような構造は通常このように見えます
type ApiResponse struct {
Code *string json:"code"`
}
また、これは参照型であるため、Goコンパイラーはエスケープ分析を実行し、指定された変数をヒープに転送できます。このような変数を頻繁に作成する場合、GCに余分な負荷がかかり、GCに使用済みメモリをすべて解放する時間がない場合は、「メモリリーク」が発生する可能性があります。
そのような状況で何ができるか:
- nil値を使用しないように外部APIを変更します。これは許容できる場合もありますが、APIを変更することは必ずしも良い考えではありません。まず、余分な作業であり、次に、そのようなやり直しから発生する可能性のあるエラーです。
- nil値を受け入れることができるように、Goコードを変更しますが、そのために参照タイプを使用しないでください。
, " "
Go
type pointerSmall struct {
Field000 *string
Field001 *string
Field002 *string
Field003 *string
Field004 *string
Field005 *string
}
,
type valueSmall struct {
Field000 string
Field001 string
Field002 string
Field003 string
Field004 string
Field005 string
}
0 , .
, .
: Go, ( - ) .
— . , . . — . , .. Go .
— , . , .
BenchmarkPointerSmall-8 1000000000 0.295 ns/op 0 B/op 0 allocs/op
BenchmarkValueSmall-8 184702404 6.51 ns/op 0 B/op 0 allocs/op
. , - - .
BenchmarkPointerSmallChain-8 1000000000 0.297 ns/op 0 B/op 0 allocs/op
BenchmarkValueSmallChain-8 59185880 20.3 ns/op 0 B/op 0 allocs/op
JSON . , jsoniter. . , .
BenchmarkPointerSmallJSON-8 49522 23724 ns/op 14122 B/op 28 allocs/op
BenchmarkValueSmallJSON-8 52234 22806 ns/op 14011 B/op 15 allocs/op
, easyjson. , .
BenchmarkPointerSmallEasyJSON-8 64482 17815 ns/op 14591 B/op 21 allocs/op
BenchmarkValueSmallEasyJSON-8 63136 17537 ns/op 14444 B/op 14 allocs/op
: , . (/ ) — .
.
type pointerBig struct {
Field000 *string
...
Field999 *string
}
type valueBig struct {
Field000 string
...
Field999 string
}
. , 0 , ( , .. ). , :
BenchmarkPointerBig-8 36787 32243 ns/op 24192 B/op 1001 allocs/op
BenchmarkValueBig-8 721375 1613 ns/op 0 B/op 0 allocs/op
. . ( , ).
BenchmarkPointerBigChain-8 36607 31709 ns/op 24192 B/op 1001 allocs/op
BenchmarkValueBigChain-8 351693 3216 ns/op 0 B/op 0 allocs/op
.
BenchmarkPointerBigJSON-8 250 4640020 ns/op 5326593 B/op 4024 allocs/op
BenchmarkValueBigJSON-8 270 4289834 ns/op 4110721 B/op 2015 allocs/op
, easyjson. . , jsoniter.
BenchmarkPointerBigEasyJSON-8 364 3204100 ns/op 2357440 B/op 3066 allocs/op
BenchmarkValueBigEasyJSON-8 380 3058639 ns/op 2302248 B/op 1063 allocs/op
: — , . — " ". (easyjson ), — .
— Nullable . sql — sql.NullBool, sql.NullString .
また、タイプについては、エンコードおよびデコード機能を説明する必要があります。
func (n NullString) MarshalJSON() ([]byte, error) {
if !n.Valid {
return []byte("null"), nil
}
return jsoniter.Marshal(n.String)
}
func (n *NullString) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, []byte("null")) {
*n = NullString{}
return nil
}
var res string
err := jsoniter.Unmarshal(data, &res)
if err != nil {
return err
}
*n = NullString{String: res, Valid: true}
return nil
}
APIで参照型を削除した結果、JSON、jsoniter、easyjson、gocqlのエンコードおよびデコード機能を備えた基本的なNullable型を備えたnanライブラリを開発しました。
Nullableタイプを使用する便利さ
そして、Nullableタイプへの切り替えについて尋ねることができる最後の質問の1つは、それらを使用するのが便利かどうかです。
私の個人的な意見は便利です。型は変数参照と同じ使用パターンを持っています。
リンクを使用する場合、
if a != nil && *a == "sometext" {
Nullableタイプでは、次のように記述します。
if a.Valid && a.String == "sometext" {