1. 程式人生 > >Golang中 json.Decoder vs json.Unmarshal

Golang中 json.Decoder vs json.Unmarshal

json的反序列化方式有兩種:

  1. Use json.Unmarshal passing the entire response string
    // func Unmarshal(data []byte, v interface{}) error
    data, err := ioutil.ReadAll(resp.Body)
    if err == nil && data != nil {
        err = json.Unmarshal(data, value)
    }
    
  2. using json.NewDecoder.Decode
    // func NewDecoder(r io.Reader) *Decoder
    // func (dec *Decoder) Decode(v interface{}) error err = json.NewDecoder(resp.Body).Decode(value)

這兩種方法看似差不多,但有不同的應用場景
3. Use json.Decoder if your data is coming from an io.Reader stream, or you need to decode multiple values from a stream of data.

For the case of reading from an HTTP request, I'd pick json.Decoder since you're obviously reading from a stream.
  1. Use json.Unmarshal if you already have the JSON data in memory.

例子

從檔案中讀入一個巨大的json陣列用json.Decoder

json.Decoder會一個一個元素進行載入,不會把整個json陣列讀到記憶體裡面

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
)

func main() {
	const jsonStream = `
	[
		{"Name": "Ed", "Text": "Knock knock."},
		{"Name": "Sam", "Text": "Who's there?"},
		{"Name": "Ed", "Text": "Go fmt."},
		{"Name": "Sam", "Text": "Go fmt who?"},
		{"Name": "Ed", "Text": "Go fmt yourself!"}
	]
`
type Message struct { Name, Text string } dec := json.NewDecoder(strings.NewReader(jsonStream)) // read open bracket t, err := dec.Token() if err != nil { log.Fatal(err) } // t的型別是json.Delim fmt.Printf("%T: %v\n", t, t) // while the array contains values for dec.More() { var m Message // decode an array value (Message) err := dec.Decode(&m) if err != nil { log.Fatal(err) } fmt.Printf("%v: %v\n", m.Name, m.Text) } // read closing bracket t, err = dec.Token() if err != nil { log.Fatal(err) } // t的型別是json.Delim fmt.Printf("%T: %v\n", t, t) }

結果:

json.Delim: [
Ed: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!
json.Delim: ]

從檔案中讀入json流用json.Decoder

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	const jsonStream = `
	{"Name": "Ed", "Text": "Knock knock."}
	{"Name": "Sam", "Text": "Who's there?"}
	{"Name": "Ed", "Text": "Go fmt."}
	{"Name": "Sam", "Text": "Go fmt who?"}
	{"Name": "Ed", "Text": "Go fmt yourself!"}
`
	type Message struct {
		Name, Text string
	}
	dec := json.NewDecoder(strings.NewReader(jsonStream))
	for {
		var m Message
		if err := dec.Decode(&m); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s: %s\n", m.Name, m.Text)
	}
}

結果:

Ed: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!

本來就以[]byte存在於記憶體中的用json.Unmarshal

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	var jsonBlob = []byte(`[
	{"Name": "Platypus", "Order": "Monotremata"},
	{"Name": "Quoll",    "Order": "Dasyuromorphia"}
]`)
	type Animal struct {
		Name  string
		Order string
	}
	var animals []Animal
	err := json.Unmarshal(jsonBlob, &animals)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", animals)
}

結果:

[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

直接讀入json陣列的兩種方式

data.json

[
{
	"site" : "npr",
	"link" : "http://www.npr.org/rss/rss.php?id=1001",
	"type" : "rss"
},
{
	"site" : "npr",
	"link" : "http://www.npr.org/rss/rss.php?id=1008",
	"type" : "rss"
},
{
	"site" : "npr",
	"link" : "http://www.npr.org/rss/rss.php?id=1006",
	"type" : "rss"
}
]

1. 得到陣列元素的地址

[]*Feed

package main

import (
	//"helloworld/hello"
	"encoding/json"
	"fmt"
	"os"
)

const dataFile = "data.json"

type Feed struct {
	Name string `json:"site"`
	URI  string `json:"link"`
	Type string `json:"type"`
}

func main() {
	//hello.Hello()
	file, err := os.Open(dataFile)
	if err != nil {
		os.Exit(1)
	}
	defer file.Close()

	var feeds []*Feed
	err = json.NewDecoder(file).Decode(&feeds)

	fmt.Printf("%T | %v\n", feeds, feeds)

	for i := range feeds {
		fmt.Println(*feeds[i])
	}

}

結果:

[]*main.Feed | [0xc0420861e0 0xc0420862a0 0xc0420862d0]
{npr http://www.npr.org/rss/rss.php?id=1001 rss}
{npr http://www.npr.org/rss/rss.php?id=1008 rss}
{npr http://www.npr.org/rss/rss.php?id=1006 rss}

2. 得到陣列元素的拷貝

[]Feed

package main

import (
	//"helloworld/hello"
	"encoding/json"
	"fmt"
	"os"
)

const dataFile = "data.json"

type Feed struct {
	Name string `json:"site"`
	URI  string `json:"link"`
	Type string `json:"type"`
}

func main() {
	//hello.Hello()
	file, err := os.Open(dataFile)
	if err != nil {
		os.Exit(1)
	}
	defer file.Close()

	var feeds []Feed
	err = json.NewDecoder(file).Decode(&feeds)

	fmt.Printf("%T | %v\n", feeds, feeds)

	// for i := range feeds {
	// 	fmt.Println(*feeds[i])
	// }

}

結果:

[]main.Feed | [{npr http://www.npr.org/rss/rss.php?id=1001 rss} {npr http://www.npr.org/rss/rss.php?id=1008 rss} {npr http://www.npr.org/rss/rss.php?id=1006 rss}]