簡介(Introduction)css
JSON(JavaScript Object Notation)是一種簡單的數據交換格式。語法上和JAVASCRIPT的對象及列表類似。這是web先後端和JavaScript程序最經常使用的數據傳遞方式,而且其餘不少地方也使用JSON。在JSON的主頁(json.org)上,對JSON的標準作了很是清晰,簡潔的定義。ios
JSON (JavaScript Object Notation) is a simple data interchange format. Syntactically it resembles the objects and lists of JavaScript. It is most commonly used for communication between web back-ends and JavaScript programs running in the browser, but it is used in many other places, too. Its home page, json.org, provides a wonderfully clear and concise definition of the standard.golang
經過JSON包,咱們能夠很是容易的使用Go對JSON數據進行讀寫操做。web
With the json package it's a snap to read and write JSON data from your Go programs.json
編碼(Encoding)c#
咱們使用Marshal方法對JSON進行編碼。
後端
To encode JSON data we use the Marshal
function.數組
func Marshal(v interface{}) ([]byte, error)
定義一個結構體,Message,並初始化。
安全
Given the Go data structure, Message
,and an instance of Message
數據結構
type Message struct { Name string Body string Time int64 } m := Message{"Alice", "Hello", 1294706395881547000}
咱們可使用變量m方法來對json.Marshal的結果進行整理。
we can marshal a JSON-encoded version of m using json.Marshal
:
b, err := json.Marshal(m)
若是編碼正確的話,err將返回nil,b將包含一個[]byte類型的JSON數據
If all is well, err
will be nil
and b
will be a []byte
containing this JSON data:
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
僅當數據結構能表示JSON的時候,才能被正確的編碼。
Only data structures that can be represented as valid JSON will be encoded:
map[string]T
(where T
is any Go type supported by the json package).Marshal方法死循環。
Marshal
to go into an infinite loop.nil
).json包僅僅可以訪問結構體的公有字段(已大寫字母開頭的字段)。所以,僅僅是公有字段纔會出如今JSON的輸出中。
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the the exported fields of a struct will be present in the JSON output.
解碼(Decoding)
使用Unmarshal方法解碼JSON數據。
To decode JSON data we use the Unmarshal
function.
func Unmarshal(data []byte, v interface{}) error
咱們須要建立一個變量來保存咱們解碼JSON數據,而後調用json.Unmarshal方法,並把須要解碼的數據和這個變量的指針,傳遞給該函數。
We must first create a place where the decoded data will be stored,and call json.Unmarshal
, passing it a []byte
of JSON data and a pointer to m
err := json.Unmarshal(b, &m)
假如b包含了一段合法的JSON數據,而且結構與m匹配,那麼err將返回nil,解碼後的數據會別存儲在m上,以下這樣:
If b
contains valid JSON that fits in m
, after the call err
will be nil
and the data from b
will have been stored in the struct m
, as if by an assignment like:
m = Message{ Name: "Alice", Body: "Hello", Time: 1294706395881547000, }
Unmarshal
方法是如何標識字段是他要存儲的呢?對於給定的鍵"Foo",Unmarshal將會檢查給定的結構體的字段(按順序優先)
How does Unmarshal
identify the fields in which to store the decoded data? For a given JSON key "Foo"
, Unmarshal
will look through the destination struct's fields to find (in order of preference):
"Foo"
(see the Go spec for more on struct tags),"Foo"
, or"FOO"
or "FoO"
or some other case-insensitive match of "Foo"
.當JSON數據和結構體不能徹底匹配時,會發生什麼?
What happens when the structure of the JSON data doesn't exactly match the Go type?
b := []byte(`{"Name":"Bob","Food":"Pickle"}`) var m Message err := json.Unmarshal(b, &m) //m和b中,都有Name,m中沒有Food,b中沒有Body和Time
Unmarshal
僅會解碼在結構體中可以找到的字段。在這種狀況下,只有「Name」字段會被m存儲,Food字段將被忽略。當你想從一個很是龐大的JSON數據中提取幾個特定的字段時,這種手段就變得很是有用。換句話說,結構體中的非公有字段將不會被解出。
Unmarshal
will decode only the fields that it can find in the destination type. In this case, only the Name field of m will be populated, and the Food field will be ignored. This behavior is particularly useful when you wish to pick only a few specific fields out of a large JSON blob. It also means that any unexported fields in the destination struct will be unaffected by Unmarshal
.
可是,假如你事先並不知道JSON數據的結構呢?
But what if you don't know the structure of your JSON data beforehand?
interface{}(空接口)描述了一個沒有任何方法的接口類型。任何一個Go類型都是由interface{}來的。
The interface{}
(empty interface) type describes an interface with zero methods. Every Go type implements at least zero methods and therefore satisfies the empty interface.
空接口類型是通用的容器類型:
The empty interface serves as a general container type:
var i interface{} i = "a string" i = 2011 i = 2.777
類型斷言可以轉換潛在數據類型到具體的數據類型
A type assertion accesses the underlying concrete type:
r := i.(float64) fmt.Println("the circle's area", math.Pi*r*r)
假如潛在類型是未知的,那麼可使用switch測試類型來決定數據類型。
Or, if the underlying type is unknown, a type switch determines the type:
switch v := i.(type) { case int: fmt.Println("twice i is", v*2) case float64: fmt.Println("the reciprocal of i is", 1/v) case string: h := len(v) / 2 fmt.Println("i swapped by halves is", v[h:]+v[:h]) default: // i isn't one of the types above }
json包使用map[string]interface{}和[]interface{}來存儲任意類型的json對象和數組。合法的JSON數據都可以存入interface{},具體的數據類型以下:
The json package uses map[string]interface{}
and []interface{}
values to store arbitrary JSON objects and arrays; it will happily unmarshal any valid JSON blob into a plain interface{}
value. The default concrete Go types are:
bool
for JSON booleans,float64
for JSON numbers,string
for JSON strings, andnil
for JSON null.解碼任意數據(Decoding arbitrary data)
假設JSON數據存在在變量b上:
Consider this JSON data, stored in the variable b
:
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
咱們並不知道它的數據結構,咱們能夠將它解碼到interface{}上。
Without knowing this data's structure, we can decode it into an interface{}
value with Unmarshal
:
var f interface{} err := json.Unmarshal(b, &f)
在這種狀況下,f的值是一個鍵爲string類型,值爲存儲在interface{}中的map類型。
At this point the Go value in f
would be a map whose keys are strings and whose values are themselves stored as empty interface values:
f = map[string]interface{}{ "Name": "Wednesday", "Age": 6, "Parents": []interface{}{ "Gomez", "Morticia", }, }
咱們可使用f的潛在類型(map[string]interface{}
)來訪問這些數據
To access this data we can use a type assertion to access `f`'s underlying map[string]interface{}
:
m := f.(map[string]interface{})
咱們能夠經過迭代map,用switch來測試這些數據類型來肯定這些值的數據類型。
We can then iterate through the map with a range statement and use a type switch to access its values as their concrete types:
for k, v := range m { switch vv := v.(type) { case string: fmt.Println(k, "is string", vv) case int: fmt.Println(k, "is int", vv) case []interface{}: fmt.Println(k, "is an array:") for i, u := range vv { fmt.Println(i, u) } default: fmt.Println(k, "is of a type I don't know how to handle") } }
經過這種方法,就可以解碼不肯定的JSON數據,而且保證數據的類型安全。
In this way you can work with unknown JSON data while still enjoying the benefits of type safety.
引用類型(Reference Types)
定義一個數據結構包含上一個例子中的數據類型。
Let's define a Go type to contain the data from the previous example:
type FamilyMember struct { Name string Age int Parents []string } var m FamilyMember err := json.Unmarshal(b, &m)
將數據解碼到FamilyMember中,獲得的數據符合預期,可是若是咱們進一步觀察就會注意到一件異常的事情。在申明語句中,咱們分配了一個FamilyMember的結構,而後將他作完指針傳遞給Unmarshal方法,可是這時,字段Parents是一個空(nil)的切片。爲了填充Parents字段,在這以後,Unmarshal
方法又分配了一個新的切片給Parents。這是Unmarshal
典型的如何支持類型引用(指針,切片,字典)的方式。
Unmarshaling that data into a FamilyMember
value works as expected, but if we look closely we can see a remarkable thing has happened. With the var statement we allocated a FamilyMember
struct, and then provided a pointer to that value to Unmarshal
, but at that time the Parents
field was a nil
slice value. To populate the Parents
field, Unmarshal
allocated a new slice behind the scenes. This is typical of how Unmarshal
works with the supported reference types (pointers, slices, and maps).
考慮一下把數據解碼到這個數據結構:
Consider unmarshaling into this data structure:
type Foo struct { Bar *Bar }
加入Bar是一個JSON對象的字段,Unmarshal
方法將會分配一個新的Bar來存放它,若是不這麼作,Bar將會指向一個空的指針。
If there were a Bar
field in the JSON object, Unmarshal
would allocate a new Bar
and populate it. If not, Bar
would be left as a nil
pointer.
在探討這個模式出現:假如你的應用只是接收一些簡單的不重複的消息,你可能會像這樣定義你的數據結構:
From this a useful pattern arises: if you have an application that receives a few distinct message types, you might define "receiver" structure like
type IncomingMessage struct { Cmd *Command Msg *Message }
發送方能夠存儲Cmd字段和/或者Msg字段做爲json對象的頂層數據,做爲他們之間想要傳遞的數據。當Unmarshal方法將數據解碼傳入IncomingMessage中時,將會分配一個數據結構來存儲JSON數據。爲了知道那個message是被處理的,程序須要鑑定的測試來保存Cmd和Msg不是空的(nil).
and the sending party can populate the Cmd
field and/or the Msg
field of the top-level JSON object, depending on the type of message they want to communicate. Unmarshal
, when decoding the JSON into an IncomingMessage
struct, will only allocate the data structures present in the JSON data. To know which messages to process, the programmer need simply test that either Cmd
or Msg
is not nil
.
json包提供了對JSON數據流的編碼(Decoder
)與解碼(Decoder
)支持。NewDecoder
和NewEncoder
函數包含了io.Reader
和 io.Writer接口類型。
func NewDecoder(r io.Reader) *Decoder func NewEncoder(w io.Writer) *Encoder
The json package provides Decoder
and Encoder
types to support the common operation of reading and writing streams of JSON data. The NewDecoder
and NewEncoder
functions wrap the io.Reader
and io.Writer
interface types.
下面這個例子演示了從表中輸入中讀取一些JSON數據,並移除除了Name以外的其餘字段,而後寫入標準輸出中。
Here's an example program that reads a series of JSON objects from standard input, removes all but the Name
field from each object, and then writes the objects to standard output:
package main import ( "encoding/json" "log" "os" ) func main() { dec := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil { log.Println(err) return } for k := range v { if k != "Name" { delete(v, k) } } if err := enc.Encode(&v); err != nil { log.Println(err) } } }
因爲無處不在的Readers和Writers,Encoder
和Decoder
類型可以應用在很是多的場景中,例如從HTTP,WebSocket或者文件中讀取和寫入JSON數據。
Due to the ubiquity of Readers and Writers, these Encoder
and Decoder
types can be used in a broad range of scenarios, such as reading and writing to HTTP connections, WebSockets, or files.
For more information see the json package documentation. For an example usage of json see the source files of the jsonrpc package.
By Andrew Gerrand