This is a creation in Article, where the information may have evolved or changed.
Sometimes the upstream field is a string type, but we want to use it as a number. Originally with one json:",string"
can support, if do not know Golang these tips, will be a lot of trouble.
Reference article: http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/
Temporarily ignores struct fields
type User struct { Email string `json:"email"` Password string `json:"password"` // many more fields…}
Temporarily Ignore password field
json.Marshal(struct { *User Password bool `json:"password,omitempty"`}{ User: user,})
Temporarily add extra fields
type User struct { Email string `json:"email"` Password string `json:"password"` // many more fields…}
Temporarily ignores the password field and adds a token field
json.Marshal(struct { *User Token string `json:"token"` Password bool `json:"password,omitempty"`}{ User: user, Token: token,})
Temporary bonding of two structs
type BlogPost struct { URL string `json:"url"` Title string `json:"title"`}type Analytics struct { Visitors int `json:"visitors"` PageViews int `json:"page_views"`}json.Marshal(struct{ *BlogPost *Analytics}{post, analytics})
A JSON cut into two structs
json.Unmarshal([]byte(`{ "url": "attila@attilaolah.eu", "title": "Attila's Blog", "visitors": 6, "page_views": 14}`), &struct { *BlogPost *Analytics}{&post, &analytics})
field for temporarily renaming a struct
type CacheItem struct { Key string `json:"key"` MaxAge int `json:"cacheAge"` Value Value `json:"cacheValue"`}json.Marshal(struct{ *CacheItem // Omit bad keys OmitMaxAge omit `json:"cacheAge,omitempty"` OmitValue omit `json:"cacheValue,omitempty"` // Add nice keys MaxAge int `json:"max_age"` Value *Value `json:"value"`}{ CacheItem: item, // Set the int by value: MaxAge: item.MaxAge, // Set the nested struct by reference, avoid making a copy: Value: &item.Value,})
Passing numbers with a string
type TestObject struct { Field1 int `json:",string"`}
This corresponding JSON is{"Field1": "100"}
If JSON is {"Field1": 100}
the error will be
Tolerate string and digital cross-transfer
If you are using Jsoniter, you can start the Blur mode to support the JSON that PHP passes over.
import "github.com/json-iterator/go/extra"extra.RegisterFuzzyDecoders()
This allows you to handle problems with strings and numbers that are not the same type. Like what
var val stringjsoniter.UnmarshalFromString(`100`, &val)
Another example
var val float32jsoniter.UnmarshalFromString(`"1.23"`, &val)
Tolerate empty arrays as objects
Another frustrating part of PHP is that if the PHP array is empty, the serialization is []
. But when it's not empty, it's serialized out {"key":"value"}
. We need to treat it as a []
{}
deal.
If you are using Jsoniter, you can start the Blur mode to support the JSON that PHP passes over.
import "github.com/json-iterator/go/extra"extra.RegisterFuzzyDecoders()
So that we can support the
var val map[string]interface{}jsoniter.UnmarshalFromString(`[]`, &val)
Support Time.time with Marshaljson
Golang will default to time. Time is serialized in string mode. If we want to represent time in other ways. Time, you need to customize the type and define Marshaljson.
type timeImplementedMarshaler time.Timefunc (obj timeImplementedMarshaler) MarshalJSON() ([]byte, error) { seconds := time.Time(obj).Unix() return []byte(strconv.FormatInt(seconds, 10)), nil}
Marshaljson is called when serializing
type TestObject struct { Field timeImplementedMarshaler}should := require.New(t)val := timeImplementedMarshaler(time.Unix(123, 0))obj := TestObject{val}bytes, err := jsoniter.Marshal(obj)should.Nil(err)should.Equal(`{"Field":123}`, string(bytes))
Support Time.time with Registertypeencoder
Jsoniter can customize the JSON codec for a type that is not your definition. For example, time. Time can be serialized with the epoch Int64
import "github.com/json-iterator/go/extra"extra.RegisterTimeAsInt64Codec(time.Microsecond)output, err := jsoniter.Marshal(time.Unix(1, 1002))should.Equal("1000001", string(output))
If you want to customize, see RegisterTimeAsInt64Codec
the implementation code
Use Marshaltext to support a map with non-string as key
Although the JSON standard supports only string as a key map. But Golang through the Marshaltext () interface, making other types available as a key to the map. For example
f, _, _ := big.ParseFloat("1", 10, 64, big.ToZero)val := map[*big.Float]string{f: "2"}str, err := MarshalToString(val)should.Equal(`{"1":"2"}`, str)
big.Float
the Marshaltext () is realized.
Use JSON. Rawmessage
If some JSON documents do not have a standard format, we can save the original text information with a string.
type TestObject struct { Field1 string Field2 json.RawMessage}var data TestObjectjson.Unmarshal([]byte(`{"field1": "hello", "field2": [1,2,3]}`), &data)should.Equal(` [1,2,3]`, string(data.Field2))
Use JSON. Number
By default, if the interface{} corresponds to a number, the case will be float64 type. If you enter a larger number, this representation can be detrimental to accuracy. So you can UseNumber()
enable json.Number
to represent numbers in strings.
decoder1 := json.NewDecoder(bytes.NewBufferString(`123`))decoder1.UseNumber()var obj1 interface{}decoder1.Decode(&obj1)should.Equal(json.Number("123"), obj1)
Jsoniter supports this usage of the standard library. At the same time, the extended behavior allows Unmarshal to support Usenumber.
json := Config{UseNumber:true}.Froze()var obj interface{}json.UnmarshalFromString("123", &obj)should.Equal(json.Number("123"), obj)
Change the naming style of a field uniformly
Often field names in JSON are not the same as field names in Go. We can use field tag to modify it.
output, err := jsoniter.Marshal(struct { UserName string `json:"user_name"` FirstLanguage string `json:"first_language"`}{ UserName: "taowen", FirstLanguage: "Chinese",})should.Equal(`{"user_name":"taowen","first_language":"Chinese"}`, string(output))
But a field to set, too troublesome. If you use Jsoniter, we can set the naming style uniformly.
import "github.com/json-iterator/go/extra"extra.SetNamingStrategy(LowerCaseWithUnderscores)output, err := jsoniter.Marshal(struct { UserName string FirstLanguage string}{ UserName: "taowen", FirstLanguage: "Chinese",})should.Nil(err)should.Equal(`{"user_name":"taowen","first_language":"Chinese"}`, string(output))
Use a private field
The standard library for Go supports only public field. Jsoniter additional support for the private field. Need to be used SupportPrivateFields()
to turn on the switch.
import "github.com/json-iterator/go/extra"extra.SupportPrivateFields()type TestObject struct { field1 string}obj := TestObject{}jsoniter.UnmarshalFromString(`{"field1":"Hello"}`, &obj)should.Equal("Hello", obj.field1)