Json and Go

Reference https://blog.go-zh.org/json-a…
Encoding
Encode的基本用法是
package main

import (
“encoding/json”
“fmt”
“os”
)

type Message struct {
Name string
Body string
Time int64
}

func main() {
message := Message{“Tom”, “Hello”, 1294706395881547000}
b, err := json.Marshal(message)
if err != nil {
fmt.Fprintf(os.Stderr, “Failed to Marshal!”)
os.Exit(1)
}

fmt.Printf(“%s”, b)
}
输出为:
{“Name”:”Tom”,”Body”:”Hello”,”Time”:1294706395881547000}
func Marshal(v interface{}) ([]byte, error)
Only data structures that can be represented as valid JSON will be encoded:

JSON objects only support string as keys.

Channel, complex, and function types cannot be encoded.
Cyclic data structures are not supported.
Pointers will be encoded as the values they point to(or null if the pointer is nil)

json package 只能access the exportede fields. 也就是首字母大写的field. 也就是在data structure中的首字母大写的field才会present in JSON output
Decoding
// We must first create a place where the decoded data will be stored
var output Message
// Please note that passing the pointer to output
decodeErr := json.Unmarshal(b, &output)
if decodeErr != nil {
fmt.Fprintf(os.Stderr, “Failed to Unmarshal json data!err:%s”, err)
os.Exit(1)
}

fmt.Printf(“%+v\n”, output)
Unmarshal是怎么确认json field与data structure的对应关系呢?,其实是通过以下来判断的(优先级从高到低).比如对于JSON Field “Foo”来说,

An exported field with a tag of “Foo”.
An exported field named “Foo”
An exported field named “FOO” or “FoO” or some other case-insensitive match of “Foo”

总结下来是: Tag -> Foo -> FOO(case-insensitive match)tag的判定规则如下
// Field appears in JSON as key “myName”.
Field int `json:”myName”`

// Field appears in JSON as key “myName” and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `json:”myName,omitempty”`

// Field appears in JSON as key “Field” (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `json:”,omitempty”`

// Field is ignored by this package.
Field int `json:”-“`

// Field appears in JSON as key “-“.
Field int `json:”-,”`
如果json data 与data structure中只有部分field匹配怎么办?
var unmatchedOutput UnmatchMessage
message1 :=
//` `代表原生字符串面值,没有转义操作,全是字符串的字面值
[]byte{`{“Name”:”Tom”,”Body”:”Hello”,”Time”:1294706395881547000}`}
decodeErr1 := json.Unmarshal(b, &unmatchedOutput)
if decodeErr1 != nil {
fmt.Fprintf(os.Stderr, “Failed to unmarshal json data! err:”, err)
os.Exit(1)
}
fmt.Printf(“%+v\n”, unmatchedOutput)
输出为
{Name:Tom Boy: Tim:0}
从上看出,Unmarshal只会decode符合上述3条件的field!This behavior is particularly useful when you wish to pick only a few specific fields out of a large JSON blob.
Generic JSON with interface{}
Decoding arbitrary data
以上2章先跳过去
Reference Types
Unmarshal会为Reference Types自动allocated a memory. 注意这里仅仅为在json 中存在的data allocate memory.
package main

import (
“encoding/json”
“fmt”
“os”
)

type FamilyMember struct {
Name string
Age int
Parents []string
}

func main() {
family := FamilyMember{“Andy”, 26, []string{“Tom”, “Lucy”}}
b, err := json.Marshal(family)
if err != nil {
fmt.Fprintf(os.Stderr, “Failed to Marshal family!err:%s”, err)
os.Exit(1)
}

fmt.Printf(“%s\n”, b)

// 注意,此时Parents slice是nil. 在Unmarshal时,会自动为其allcated memory.
var output FamilyMember
decodeErr := json.Unmarshal(b, &output)
if decodeErr != nil {
fmt.Fprintf(os.Stderr, “Failed to unmarshal!err:%s”, err.Error())
os.Exit(1)
}

fmt.Printf(“%+v\n”, output)
}
对于指针也是一样的
package main

import (
“encoding/json”
“fmt”
“os”
)

type Bar int
type Foo struct {
Bar *Bar
}

func main() {
b := []byte(`{“Bar”:1234}`)
var data Foo
err := json.Unmarshal(b, &data)
if err != nil {
fmt.Fprintf(os.Stderr, “Failed to unmarshal!err:%s”, err.Error())
os.Exit(1)
}
fmt.Printf(“%+v\n”, data)
fmt.Printf(“%+v\n”, *(data.Bar))
}
输出为:
{Bar:0xc42001a120} // 注意此时的地址不为nil了,因为在Unmarshal已经为其allocated了memory
1234
但是需要注意,Unmarshal只会为json data匹配的field 分配内存,对于没有匹配的,可能还是nil. 所以对于如下的structure,在使用之前还需要认为的判断是否为nil.
type IncomingMessage struct {
Cmd *Command
Msg *Message
}
Streaming Encoders and Decoders
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)
}
}
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理