Gehe zu: So verwenden Sie Nullwerte ohne Verwendung von Referenztypen



Basierend auf Bildern von gopherize.me



Sehr oft müssen wir mit Go-Code mit verschiedenen HTTP-APIs arbeiten oder selbst als HTTP-Dienst fungieren.



Einer der häufigsten Fälle: Wir empfangen Daten in Form einer Struktur aus der Datenbank, senden die Struktur an die externe API, als Antwort erhalten wir eine andere Struktur, transformieren sie irgendwie und speichern sie in der Datenbank.



Mit anderen Worten: Eine solche Verarbeitung erfordert nicht viele separate Operationen mit den Anforderungs- und Antwortstrukturen.



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 .



Außerdem müssen Sie für den Typ die Codierungs- und Decodierungsfunktionen beschreiben



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
}


Als Ergebnis der Beseitigung von Referenztypen in der API entwickelte ich eine Nanobibliothek mit grundlegenden Nullable-Typen mit Codierungs- und Decodierungsfunktionen für JSON, jsoniter, easyjson, gocql.



Bequeme Verwendung von Nullable-Typen



Und eine der letzten Fragen, die Sie zum Wechsel zu Nullable-Typen stellen können, ist, ob es zweckmäßig ist, sie zu verwenden.



Meine persönliche Meinung ist praktisch, Typen haben das gleiche Verwendungsmuster wie variable Referenzen.



Wenn wir einen Link verwenden, schreiben wir



if a != nil && *a == "sometext" {


Mit einem Nullable-Typ schreiben wir



if a.Valid && a.String == "sometext" {



All Articles