golang official standard for our json parsing library - encoding/json
and, in most cases, it has been good enough. But this analytical package has a big problem - performance. It is not fast enough, if we develop high-performance, high concurrency network services can not meet, then you need a high-performance json parsing library, currently have a relatively high performance json-iterator
and easyjson
.
Now we need to introduce a high-performance json parsing library, here for json-iterator
example, but we do not replace all rest assured, it is possible to test a small area, and this time we need to resolve two libraries exist, so this time we how to choose the resolver library to compile and run we need it?
Solution to the above problems is conditional compilation. Go language provides us with the basis to solve this problem is to compile constraint tags.
Unified JSON library
Let's give an example to see the results. Now we need two libraries exist, so we come unified usage of these two libraries (refer adapter mode), where we use a custom json
package to fit encoding/json
and json-iterator
.
json/json.go
// +build !jsoniter package json import ( "encoding/json" "fmt" ) func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { fmt.Println("Use [encoding/json] package") return json.MarshalIndent(v,prefix,indent) }
json/jsoniter.go
// +build jsoniter package json import ( "fmt" "github.com/json-iterator/go" ) var ( json = jsoniter.ConfigCompatibleWithStandardLibrary ) func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { fmt.Println("Use [jsoniter] package") return json.MarshalIndent(v,prefix,indent) }
Directory structure is as follows:
json
├── json.go
└── jsoniter.go
Example to MarshalIndent
function as an example, we found json
two go under the package has MarshalIndent
defined functions, and the same signature, but they are also using different json parsing library implementation, and this is the result of adapting the packaging of our unity, unified call.
Demo demo
To distinguish calls which json library specific implementation, the print log to distinguish. Now we use the json.MarshalIndent
test.
package main import ( "fmt" "json" ) func main() { u := user{"Mike", 30} b, err := json.MarshalIndent(u, "", " ") if err != nil { fmt.Println(err) } else { fmt.Println(string(b)) } } type user struct { Name string Age int }
Very simple to use, to a user
structure of an object into json string and print it out. We run go run main.go
see the results.
Use [encoding/json] package { "Name": "Mike", "Age": 30 }
We default to maintain encoding/json
the same library the way. Now we compile and run in a different way:
go run -tags=jsoniter main.go
This run and the last difference is that we added -tags=jsoniter
, and then use json-iterator
the json library, which is conditional compilation selective, we aim to achieve a small part of the testing of new json library.
Conditional compilation
We found that the key lies in conditional compilation -tags=jsoniter
, which is -tags
one of the signs, which is the condition for us to provide the Go language compiler way.
Well, look back when we first started json/json.go
, json/jsoniter.go
the top two Go file, there is a comment line:
// +build !jsoniter
// +build jsoniter
These two lines are the key conditions for the Go language compiler. +build
It can be understood as conditional compilation statement keyword tags, conditions, followed by the tags.
// +build !jsoniter
Represents, tags not the jsoniter
time to compile the Go file. // +build jsoniter
He represents, tags is jsoniter
the time to compile the Go file.
In other words, these two conditions are mutually exclusive, and only when tags=jsoniter
the time will be used json-iterator
, otherwise use encoding/json
.
summary
Use conditional compilation, we aim to achieve the flexibility to choose the json parsing library, and tags is only one part, Go language also allows conditional compilation based on Go file suffix.