Go Language blog JSON and go

Source: Internet
Author: User
Tags uppercase letter
This is a creation in Article, where the information may have evolved or changed.

Introduction (Introduction)

JSON (JavaScript Object Notation) is a simple data interchange format. Syntax is similar to JavaScript objects and lists. This is the most commonly used method of data transfer between the Web front and back end and JavaScript programs, and JSON is used in many other places as well. On the JSON home page (json.org), the JSON standard is clearly and concisely defined.

JSON (JavaScript Object Notation) is a simple data interchange format. Syntactically it resembles the objects and lists of JavaScript. It is a 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.

With the JSON package, we can use go to read and write JSON data very easily.

With the JSON package it's a snap to read and write JSON data from your Go programs.

Encoding (Encoding)

We useMarshal方法对JSON进行编码。

To encode JSON data we use the Marshal function.

func Marshal(v interface{}) ([]byte, error)

Define a struct,Message,并初始化。

Given the GO data structure, Message , and an instance ofMessage

type Message struct {    Name string    Body string    Time int64}m := Message{"Alice", "Hello", 1294706395881547000}

We can use the variable m方法来对json.Marshal的结果进行整理。

We can marshal a json-encoded version of M using json.Marshal :

b, err := json.Marshal(m)

If the encoding is correct, err will return nil,b will contain a []byte type of JSON data

If all are well, would be and would be err nil b a []byte containing this JSON data:

b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)

The data structure can be encoded correctly only when it represents the JSON.

Only data structures the can be represented as valid JSON would be encoded:

    • The key value of a JSON object supports only string types; that is, the encoded data type must be Map[string]t (T can be any data type supported by the JSON package for Go)
    • JSON objects only support strings as keys; To encode a go map type it must being of the the form map[string]T (where is any T Go type supported by the JSON package).
    • Channel type (chan), composite types and functions cannot be encoded
    • Channel, complex, and function types cannot be encoded.
    • Data structure types that do not support looping;Marshal方法死循环。
    • Cyclic data structures is not supported; They'll cause to go into an Marshal infinite loop.
    • The pointer type will be encoded as the pointer to the stop (if the null pointer is "NULL", the pointer value is nil)
    • Pointers'll be encoded as the values they point to (or ' null ' if the pointer is nil ).

The JSON package only has access to the public fields of the struct (fields that begin with capital letters). Therefore, only public fields appear in the output of JSON.

The JSON package is only accesses the exported fields of the struct types (those, begin with a uppercase letter). Therefore the the the exported fields of a struct'll is present in the JSON output.

Decoding (decoding)

UseUnmarshal方法解码JSON数据。

To decode JSON data we use the Unmarshal function.

func Unmarshal(data []byte, v interface{}) error

We need to create a variable to hold we decode the JSON data and then calljson.Unmarshal方法,并把需要解码的数据和这个变量的指针,传递给该函数。

We must first create a place where the decoded data would be Stored,and call json.Unmarshal passing it a of []byte JSON data and a P Ointer tom

err := json.Unmarshal(b, &m)

If B contains a valid JSON data and the structure matches m, then err will return nil, and the decoded data will not be stored on M, as follows:

If b contains valid JSON that fits in, after the call would be m and the data from would have err nil b been Stored m in the struct, as if by a assignment like:

m = Message{    Name: "Alice",    Body: "Hello",    Time: 1294706395881547000,}

UnmarshalHow does the method identify the field that he wants to store? For the given key "Foo",Unmarshal将会检查给定的结构体的字段(按顺序优先)

How does identify the ' fields ' Unmarshal which to store the decoded data? For a given JSON key "Foo" , would look Unmarshal through the destination struct ' s fields to find (in order of preference):

    • A public field tag: "Foo" (see Go Spec)
    • An exported field with a tag "Foo" of (see the Go spec for more on struct tags),
    • A public field name of "Foo", or
    • An exported field named "Foo" , or
    • "foo", "foo", case-insensitive, match Foo's public field
    • An exported field named "FOO" or "FoO" or some other case-insensitive match of "Foo" .

What happens when the JSON data and the struct do not exactly match?

What happens when the structure of the JSON data doesn ' t exactly match the Go type?

UnmarshalOnly the fields that can be found in the struct are decoded. In this case, only the "Name" field will be stored by M, and the food field will be ignored. This is useful when you want to extract several specific fields from a very large JSON data. In other words, non-public fields in the struct will not be solved.

UnmarshalWould decode only this fields, it can find in the destination type. In this case, only the Name field of M would be populated, and the food field would be ignored. This behavior is particularly useful if you wish to pick only a few specific the fields out of a large JSON blob. It also means that any unexported fields in the destination struct would be unaffected by Unmarshal .

But what if you didn't know the structure of the JSON data beforehand?

But what if you don ' t know the structure of your JSON data beforehand?

(Common JSON type interface{}) Generic JSON with interface{}

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 type is a common container type:

The empty interface serves as a general container type:

var i interface{}i = "a string"i = 2011i = 2.777

Type assertion can convert a potential data type to a specific data type

A type assertion accesses the underlying concrete type:

r := i.(float64)fmt.Println("the circle's area", math.Pi*r*r)

If the potential type is unknown, you can use the switch test type to determine the data type.

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}

The JSON package usesmap[string]interface{}和[]interface{}来存储任意类型的json对象和数组。合法的JSON数据都能够存入interface{},具体的数据类型如下:

The JSON package uses map[string]interface{} and []interface{} values to store arbitrary JSON objects and arrays; it'll happily unmarshal any Val ID JSON blob into a plain interface{} value. The default concrete Go types are:

    • Convert Boolean object to bool
    • boolFor JSON Booleans,
    • Number is float64
    • float64For JSON numbers,
    • string literal
    • stringFor JSON strings, and
    • Null is nil
    • nilFor JSON null.

Decode arbitrary data (decoding arbitrary)

Suppose the JSON data exists on variable B:

Consider this JSON data, stored in the variable b :

b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

We don't know its data structure, we can decode it tointerface{}上。

Without knowing this data ' s structure, we can decode it to an interface{} value with Unmarshal :

var f interface{}err := json.Unmarshal(b, &f)

In this case, the value of f is a key of type string and the value is the map type stored in interface{}.

At this point the Go value in f would is a map whose keys is strings and whose values is themselves stored as empty Interface values:

f = map[string]interface{}{    "Name": "Wednesday",    "Age":  6,    "Parents": []interface{}{        "Gomez",        "Morticia",    },}

We can use the potential type of F ( map[string]interface{} ) to access this data

To access the This data we can use a type assertion to access ' F ' s underlying map[string]interface{} :

m := f.(map[string]interface{})

We can determine the data type of these values by iterating over the map and testing the data types with switch.

We can then iterate through the map with a range statement and use a type switch to access its values as their concrete ty Pes:

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")    }}

In this way, it is possible to decode the indeterminate JSON data and ensure the type safety of the data.

In this is the unknown JSON data while still enjoying the benefits of type safety.

Reference type (Reference Types)

Defines a data structure that contains the type of the previous example.

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)

Decodes the data into FamilyMember中,得到的数据符合预期,但是如果我们进一步观察就会注意到一件异常的事情。在申明语句中,我们分配了一个FamilyMember的结构,然后将他做完指针传递给Unmarshal方法,但是这时,字段Parents是一个空(nil)的切片。为了填充Parents字段,在这之后,Unmarshal a method and assigns a new slice to the Parents。这是Unmarshal typical way of how to support type references (pointers, slices, dictionaries).

Unmarshaling that data to a FamilyMember value works as expected, but if we look closely we can see a remarkable thing have Happ Ened. With the Var statement we allocated a FamilyMember struct, and then provided a pointer Unmarshal to that value to, but at that time t He Parents Field was a nil slice value. Parentsto populate the field, Unmarshal allocated a new slice behind the scenes. This was typical of how Unmarshal works with the supported reference types (pointers, slices, and maps).

Consider decoding the data to this structure:

Consider unmarshaling into this data structure:

type Foo struct {    Bar *Bar}

Joining Bar is a field of a JSON object, and the Unmarshal method assigns a new bar to hold it, and if you do not, bar will point to an empty pointer.

If There were a Bar field in the JSON object, Unmarshal would allocate a new and Bar populate it. If not, would is left as Bar a nil pointer.

In exploring this pattern appears: If your app just receives some simple, non-repetitive messages, you might define your data structure like this:

From this a useful pattern arises:if you has an application that receives a few distinct message types, you might define "Receiver" structure like

type IncomingMessage struct {    Cmd *Command    Msg *Message}

The sender can store the cmd field and/or the MSG field as the top-level data for the JSON object as the data they want to pass between them. WhenUnmarshal方法将数据解码传入IncomingMessage中时,将会分配一个数据结构来存储JSON数据。为了知道那个message是被处理的,程序需要鉴定的测试来保存Cmd和Msg不是空的(nil).

And the sending party can populate Cmd the field and/or Msg the field of the top-level JSON object, depending on the T Ype of message they want to communicate. When Unmarshal decoding IncomingMessage the JSON to an struct, would 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 was not Msg nil .

(Stream encoder and decoder) Streaming encoders and decoders

The JSON package provides encoding ( Decoder ) and decoding () support for the JSON data stream Decoder . NewDecoderand NewEncoder functions contain the io.Reader andio.Writer接口类型。

func NewDecoder(r io.Reader) *Decoderfunc NewEncoder(w io.Writer) *Encoder

The JSON package provides and types to the Decoder Encoder common operation of reading and writing streams of JSON dat A. The and NewDecoder NewEncoder functions wrap the and io.Reader io.Writer interface types.

The following example demonstrates reading some JSON data from a table input and removing fields other than name, and then writing to standard output.

Here's a example program that reads a series of JSON objects from standard input, removes all, and the Name field from EAC H object, and then writes the objects to standard output:

package mainimport (    "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)        }    }}

Because of ubiquitous readers and writers, Encoder and Decoder types can be applied in very many scenarios, such as reading and writing JSON data from http,websocket or files.

Due to the ubiquity of Readers and writers, these Encoder and Decoder types can is used in a broad range of scenarios, such as Reading and writing to HTTP connections, WebSockets, or files.

Reference references

For more information see the JSON package documentation. For a example usage of JSON see the source files of the the JSONRPC package.

by Andrew Gerrand

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.