Aller: Comment utiliser des valeurs nulles sans utiliser de types de référence



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" {



All Articles