Go:JSON基础

55 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情


import "encoding/json"

encoding

编码成JSON数据

func Marshal(v interface{}) ([]byte, error)
type Message struct {
    Name string
    Body string
    Time int64
}
m := Message{"Alice", "Hello", 1294706395881547000}
b, err := json.Marshal(m)

只有可以表示为json的数据结构能编码成json map数据类型也可以编码为json

var m = map[string]interface{}{
    "name": "Alice",
    "age":  15,
}
b, err := json.Marshal(m)

decoding

解码JSON数据

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

将json数据data解码存储到v中;

var n Message
// 将解码后的数据存储到n中
err =json.Unmarshal(b, &n)
  • Unmarshal方法是如何识别解码后的数据应该对应哪个字段的呢?

比如对于json的keyname,Unmarshal会在指定的结构(Message)中查找匹配的字段(字段必须以大写字母开头,因为只有导出的字段才能被编码/解码为JSON);

  • 当JSON的数据结构与Go数据类型不完全匹配怎么办?

Unmarshal只会解码能匹配到的字段,没有匹配到的就空着;

  • 如果事先不知道JSON数据的结构怎么办?应该用什么数据结构来接收?

空接口:interface{}

关于接口与空接口:

接口类型是由一组方法签名组成的集合,实现接口的方式就是实现这个接口的所有方法

空接口:指定了零个方法的接口;

每个Go类型都至少实现了零个方法,所以相当于实现了空接口; 可以用类型断言获取底层数据;

类型断言提供了访问接口值底层具体值的方式;

t := i.(T)

该语句断言接口值 i 保存了具体类型 T,并将其底层类型为 T 的值赋予变量 t。

若 i 并未保存 T 类型的值,该语句就会触发一个panic。

为了判断一个接口值是否保存了一个特定的类型,类型断言可返回两个值:其底层值以及一个报告断言是否成功的布尔值。

t, ok := i.(T)

若 i 保存了一个 T类型的值,那么 t 将会是其底层值,而 ok 为 true。

否则,ok 将为 false 而 t 将为 T 类型的零值,程序并不会产生恐慌。

如果不知道底层类型,则可以用switch来确定

var f interface{}
err = json.Unmarshal(y, &f)
if err == nil {
    m := f.(map[string]interface{})
    for k, v := range m {
        switch vv := v.(type) {
        case string:
            fmt.Println(k, " is string ", vv)
        case float64:
            fmt.Println(k, " is float64 ", vv)
        case int:
            fmt.Println(k, " is int ", vv)
        case bool:
            fmt.Println(k, " is bool ", vv)
        case []interface{}:
            fmt.Println(k, " is array ")
            for i, a := range vv {
                fmt.Println(i, " : ", a)
            }
        default:
            fmt.Println(k, " don't know ", vv)
        }
    }
}

这种方式的好处是使用未知的JSON数据的同时仍然做到类型安全;

json 包使用 map[string]interface{}[]interface{} 来存储 JSON 对象和数组;它会愉快地将任何有效的 JSON blob 解组为普通 interface{} 值。默认的具体 Go 类型是:

bool对应 JSON 布尔值,

float64、整数对应 JSON 数值,

数组和切片值编码为 JSON 数组,

string对于 JSON 字符串,

nil对于 JSON 为空。

也可以直接解码成map[string]interface{}

var y = []byte(`{"name":"Bob","age":20,"score":96.4,"first":false,"hobby":["eat","game"]}`)
var c = make(map[string]interface{})
err := json.Unmarshal(y, &c)
if err == nil {
	fmt.Println(c)
}

流编码器和流解码器

json 包提供Decoder和Encoder类型来支持读取和写入 JSON 数据流的常见操作;

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

从标准输入中读取JSON对象;

由于 Reader 和 Writers 无处不在,这些EncoderDecoder类型可用于广泛的场景,例如读取和写入 HTTP 连接、WebSocket 或文件