Basé sur des images de gopherize.me
Très souvent, à partir du code Go, nous devons travailler avec diverses API HTTP ou agir nous-mêmes comme un service HTTP.
Un des cas les plus courants: nous recevons des données sous la forme d'une structure de la base de données, envoyons la structure à l'API externe, en réponse nous recevons une autre structure, la transformons en quelque sorte et la sauvegardons dans la base de données.
En d'autres termes: un tel traitement ne nécessite pas de nombreuses opérations séparées avec les structures de demande et de réponse.
API , , nil - -nil .
type ApiResponse struct {
Code *string json:"code"`
}
, , Go escape . — GC " ", GC .
:
- API , nil . , API — : -, , - — , .
- Go , nil , .
, " "
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 .
De plus, pour le type, vous devrez décrire les fonctions d'encodage et de décodage.
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
}
Suite à la suppression des types de référence dans l'API, j'ai développé une bibliothèque nan , avec des types Nullable de base avec des fonctions d'encodage et de décodage pour JSON, jsoniter, easyjson, gocql.
Facilité d'utilisation des types Nullable
Et l'une des dernières questions que vous pouvez vous poser sur le passage aux types Nullable est de savoir s'ils sont pratiques à utiliser.
Mon opinion personnelle est pratique, les types ont le même modèle d'utilisation que les références variables.
Lors de l'utilisation d'un lien, nous écrivons
if a != nil && *a == "sometext" {
Avec un type Nullable, on écrit
if a.Valid && a.String == "sometext" {