type myFloat float64
// This has a pointer receiver.
func (f *myFloat) MarshalJSON()([]byte, error){return[]byte(fmt.Sprintf("%.2f", *f)), nil
}func main(){ f := myFloat(1.0 / 3.0) // When encoding a value, the MarshalJSON method is used.
// 得到 0.33
js, err := json.Marshal(&f)if err != nil { log.Fatal(err)} fmt.Printf("%s\n", js) // When encoding a value, the MarshalJSON method is ignored.
// 得到默认的 0.3333333333333333
js, err= json.Marshal(f)if err != nil { log.Fatal(err)} fmt.Printf("%s", js)}
部分 JSON 解码
如果你只需要处理 JSON 中的一小部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Let's say that the only thing we're interested in is processing the "genres" array in
// the following JSON object
js:=`{"title": "Top Gun", "genres": ["action", "romance"], "year": 1986}`// Decode the JSON object to a map[string]json.RawMessage type. The json.RawMessage
// values in the map will retain their original, un-decoded, JSON values.
varmmap[string]json.RawMessageerr:=json.NewDecoder(strings.NewReader(js)).Decode(&m)iferr!=nil{log.Fatal(err)}// We can then access the JSON "genres" value from the map and decode it as normal using
// the json.Unmarshal() function.
vargenres[]stringerr=json.Unmarshal(m["genres"],&genres)iferr!=nil{log.Fatal(err)}fmt.Printf("genres: %v\n",genres)
js:=`10`varnanydec:=json.NewDecoder(strings.NewReader(js))dec.UseNumber()// Call the UseNumber() method on the decoder before using it.
err:=dec.Decode(&n)iferr!=nil{log.Fatal(err)}// Type assert the any value to a json.Number, and then call the Int64() method
// to get the number as a Go int64.
nInt64,err:=n.(json.Number).Int64()iferr!=nil{log.Fatal(err)}// Likewise, you can use the String() method to get the number as a Go string.
nString:=n.(json.Number).String()fmt.Printf("type: %T; value: %v\n",n,n)fmt.Printf("type: %T; value: %v\n",nInt64,nInt64)fmt.Printf("type: %T; value: %v\n",nString,nString)
// Note that there are no struct tags on the Movie struct itself.
type Movie struct { ID int64
CreatedAt time.Time
Title string
Year int32
Runtime int32
Genres []string
Version int32
}// Implement a MarshalJSON() method on the Movie struct, so that it satisfies the
// json.Marshaler interface.
func (m Movie) MarshalJSON()([]byte, error){ // Declare a variable to hold the custom runtime string (this will be the empty
// string "" by default).
var runtime string
// If the value of the Runtime field is not zero, set the runtime variable to be a
// string in the format "<runtime> mins".
if m.Runtime !=0{runtime= fmt.Sprintf("%d mins", m.Runtime)} // Create an anonymous struct to hold the data for JSON encoding. This has exactly
// the same fields, types and tags as our Movie struct, except that the Runtime
// field here is a string, instead of an int32. Also notice that we don't include
// a CreatedAt field at all (there's no point including one, because we don't want
// it to appear in the JSON output).
aux := struct { ID int64 `json:"id"` Title string `json:"title"` Year int32 `json:"year,omitempty"` Runtime string `json:"runtime,omitempty"` // This is a string.
Genres []string `json:"genres,omitempty"` Version int32 `json:"version"`}{ // Set the values for the anonymous struct.
ID: m.ID,
Title: m.Title,
Year: m.Year,
Runtime: runtime, // Note that we assign the value from the runtime variable here.
Genres: m.Genres,
Version: m.Version,
}return json.Marshal(aux)}
// Notice that we use the - directive on the Runtime field, so that it never appears
// in the JSON output.
typeMoviestruct{IDint64`json:"id"`CreatedAttime.Time`json:"-"`Titlestring`json:"title"`Yearint32`json:"year,omitempty"`Runtimeint32`json:"-"`Genres[]string`json:"genres,omitempty"`Versionint32`json:"version"`}func(mMovie)MarshalJSON()([]byte,error){// Create a variable holding the custom runtime string, just like before.
varruntimestringifm.Runtime!=0{runtime=fmt.Sprintf("%d mins",m.Runtime)}// Define a MovieAlias type which has the underlying type Movie. Due to the way that
// Go handles type definitions (https://golang.org/ref/spec#Type_definitions) the
// MovieAlias type will contain all the fields that our Movie struct has but,
// importantly, none of the methods.
typeMovieAliasMovie// Embed the MovieAlias type inside the anonymous struct, along with a Runtime field
// that has the type string and the necessary struct tags. It's important that we
// embed the MovieAlias type here, rather than the Movie type directly, to avoid
// inheriting the MarshalJSON() method of the Movie type (which would result in an
// infinite loop during encoding).
aux:=struct{MovieAliasRuntimestring`json:"runtime,omitempty"`}{MovieAlias:MovieAlias(m),Runtime:runtime,}returnjson.Marshal(aux)}
解码类型
JSON type
Supported Go types
boolean
bool
string
string
number
int*,uint*,float*,rune
array
array,slice
object
struct, map
JSON 错误分类
对于面向公众的 API,错误消息本身并不理想。有些令人困惑且难以理解,或暴露了底层 API 细节信息。