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 use Marshal method to encode JSON.



To encode JSON data we use theMarshalfunction.


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


Define a struct,Message,And initialize。



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 method to organize the results of json.Marshal.



We can marshal a json-encoded version of M usingjson.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 beerrnilba[]bytecontaining 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 formmap[string]T(where is anyTGo 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 Method endless loop。
    • Cyclic data structures is not supported; They'll cause to go into anMarshalinfinite 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 isnil).


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 method decodes JSON data.



To decode JSON data we use theUnmarshalfunction.


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


We need to create a variable to hold we decode the JSON data and then calljson.Unmarshal method, and pass the data to be decoded and a pointer to this variable to the function.



We must first create a place where the decoded data would be Stored,and calljson.Unmarshalpassing it a of[]byteJSON 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:



Ifbcontains valid JSON that fits in, after the call would bemand the data from would haveerrnilbbeen Storedmin 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 will check the fields of the given structure (order first)



How does identify the ' fields 'Unmarshalwhich to store the decoded data? For a given JSON key"Foo", would lookUnmarshalthrough 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 byUnmarshal.



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 {} (empty interface) describes an interface type without any methods. Any Go type is derived from interface {}.



Theinterface{}(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:


interface {} (empty interface) describes an interface type without any methods. Any Go type is derived from interface {}.


The JSON package uses map [string] interface {} and [] interface {} to store arbitrary types of json objects and arrays. Valid JSON data can be stored in interface {}. The specific data types are as follows:



The JSON package usesmap[string]interface{}and[]interface{}values to store arbitrary JSON objects and arrays; it'll happily unmarshal any Val ID JSON blob into a plaininterface{}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 variableb:


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 aninterface{}value withUnmarshal:


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 infwould 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 underlyingmap[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, the data obtained is as expected, but if we observe further, we will notice an abnormal thing. In the statement, we allocate a FamilyMember structure, and then pass the pointer to the Unmarshal method, but at this time, the Parents field is a nil slice. To fill the Parents field, after that, Unmarshala method and assigns a new slice to the Parents. This is the Unmarshal typical way of how to support type references (pointers, slices, dictionaries).



Unmarshaling that data to aFamilyMembervalue works as expected, but if we look closely we can see a remarkable thing have Happ Ened. With the Var statement we allocated aFamilyMemberstruct, and then provided a pointerUnmarshalto that value to, but at that time t HeParentsField was anilslice value.Parentsto populate the field,Unmarshalallocated a new slice behind the scenes. This was typical of howUnmarshalworks 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 theUnmarshalmethod assigns a new bar to hold it, and if you do not, bar will point to an empty pointer.



If There were aBarfield in the JSON object,Unmarshalwould allocate a new andBarpopulate it. If not, would is left asBaranilpointer.



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. When the Unmarshal method decodes the data into the IncomingMessage, it will allocate a data structure To store JSON data. In order to know which message is being processed, the program needs a qualified test to save that Cmd and Msg are not empty (nil).



And the sending party can populateCmdthe field and/orMsgthe field of the top-level JSON object, depending on the T Ype of message they want to communicate. WhenUnmarshaldecodingIncomingMessagethe 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 eitherCmdor was notMsgnil.



(Stream encoder and decoder) Streaming encoders and decoders



The JSON package provides encoding (Decoder) and decoding () support for the JSON data streamDecoder.NewDecoderandNewEncoderfunctions contain theio.Readerandio.Writer接口类型。


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


The JSON package provides and types to theDecoderEncodercommon operation of reading and writing streams of JSON dat A. The andNewDecoderNewEncoderfunctions wrap the andio.Readerio.Writerinterface 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 theNamefield from EAC H 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)
        }
    }
}


Because of ubiquitous readers and writers,EncoderandDecodertypes 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, theseEncoderandDecodertypes 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.