golang的json编码与解码

什么是json?

  • json指的是JavaScript对象标记法(JavaScript Object Notation)
  • json是一种轻量级的数据交换格式。
    (数据格式以键值对的形式出现:name:value)
  • json具有自我描述性且易于理解。
  • json独立于编程语言。
    (json实际上是一个字符串,几乎所有语言都可以处理字符串数据)

因此在WEB开发过程中,使用json格式承载http信息十分方便,不用考虑发送方和接收方的语言差异。

虽然json只是一个字符串,但是其数据也是有数据类型之分的。对于格式转换仍然需要数据类型的映射。对于不同语言的语言特性,json会有不同的数据类型映射关系。

golang与json的数据类型映射

golang->json

golangjson
boolBoolean
int、float等数字类型Number
stringString
[]byte(base64编码)String
structObject,递归打包
array/sliceArray
mapObject
interface{}按实际情况转换
nilnull
channel、funcUnsupportedTypeError

json->golang

jsongolang
Booleanbool
Numberint、float等数字类型
Stringstring
Array[]interface{}
Objectmap[string]interface{}
nullnil

golang的json编码

最常用的编码、解码方法有两种:

结构体定义

type MallDetailForSave struct {
	ID       uint64        `json:"id"`
	Name     string        `json:"name"`
	Limit    map[int]int64 `json:"limit"`
	SpecID   []uint32      `json:"spec_id"`
	SpecTime TimeLimit     `json:"spec_time"`
	Sort     int           `json:"sort"`
}

type TimeLimit struct {
	Start int `json:"start"`
	End   int `json:"end"`
}

json.Marshal()进行编码

func TestMarshal(t *testing.T) {
	mall := &MallDetailForSave{}
	mall.ID = 123
	mall.Name = "123"
	mall.Limit = make(map[int]int64, 0)
	mall.Limit[1] = 7
	mall.Limit[2] = 8
	mall.Limit[3] = 9
	mall.Limit[4] = 10
	mall.SpecID = make([]uint32, 1)
	mall.SpecID[0] = 77596687
	mall.SpecTime = &TimeLimit{
		Start: 1,
		End:   2,
	}
	mall.Sort = 1
	body, err := json.Marshal(&mall)
	if err != nil {
		fmt.Printf("err=%+v\n", err)
		return
	}
	fmt.Printf("body=%s\n", string(body))
}
=== RUN   TestMarshal
body={"id":123,"name":"123","limit":{"1":7,"2":8,"3":9,"4":10},"spec_id":[77596687],"spec_time":{"start":1,"end":2},"sort":1}
--- PASS: TestMarshal (0.00s)
PASS

json.NewEncoder()进行编码

func TestNewencoder(t *testing.T) {
	mall := &MallDetailForSave{}
	mall.ID = 123
	mall.Name = "123"
	mall.Limit = make(map[int]int64, 0)
	mall.Limit[1] = 7
	mall.Limit[2] = 8
	mall.Limit[3] = 9
	mall.Limit[4] = 10
	mall.SpecID = make([]uint32, 1)
	mall.SpecID[0] = 77596687
	mall.SpecTime = &TimeLimit{
		Start: 1,
		End:   2,
	}
	mall.Sort = 1
	buffer := &bytes.Buffer{}
	err := json.NewEncoder(buffer).Encode(mall)
	if err != nil {
		fmt.Printf("err=%+v\n", err)
		return
	}
	fmt.Printf("body=%s\n", buffer.String())
}
=== RUN   TestNewencoder
body={"id":123,"name":"123","limit":{"1":7,"2":8,"3":9,"4":10},"spec_id":[77596687],"spec_time":{"start":1,"end":2},"sort":1}

--- PASS: TestNewencoder (0.00s)
PASS

golang的json解码

对应的,常用解码方式也有两种:

json.Unmarshal()进行解码

func TestUnmarshal(t *testing.T) {
	mall := &MallDetailForSave{}
	body := "{\"id\":123,\"name\":\"123\",\"point\":100,\"limit\":{\"1\":7,\"2\":8,\"3\":9,\"4\":10},\"spec_id\":[77596687],\"spec_time\":{\"start\":1,\"end\":2},\"sort\":1,\"gtype\":0}\n"
	
	err := json.Unmarshal([]byte(body), &mall)
	if err != nil {
		fmt.Printf("err=%+v\n", err)
		return
	}
	fmt.Printf("mall=%+v\n", mall)
}
=== RUN   TestUnmarshal
mall=&{ID:123 Name:123 Limit:map[1:7 2:8 3:9 4:10] SpecID:[77596687] SpecTime:{Start:1 End:2} Sort:1}
--- PASS: TestUnmarshal (0.00s)
PASS

我们可以观察到:在字符串body中,并没有严格按照结构体的字段属性定义,而是多了两个字段,但是这样并不影响解码操作。因此在json解码过程中,解码器只会寻找可以匹配上的键值对,无法匹配的自动丢弃。这样极大地增加了解码的灵活性,不计个数,不计顺序。

json.TestUnnewdecoder()进行解码

func TestUnnewdecoder(t *testing.T) {
	mall := &MallDetailForSave{}

	body := "{\"id\":123,\"name\":\"123\",\"point\":100,\"limit\":{\"1\":7,\"2\":8,\"3\":9,\"4\":10},\"spec_id\":[77596687],\"spec_time\":{\"start\":1,\"end\":2},\"sort\":1,\"gtype\":0}\n"
	err := json.NewDecoder(strings.NewReader(body)).Decode(&mall)
	if err != nil {
		fmt.Printf("err=%+v\n", err)
		return
	}
	fmt.Printf("mall=%+v\n", mall)
}

=== RUN   TestUnnewdecoder
mall=&{ID:123 Name:123 Limit:map[1:7 2:8 3:9 4:10] SpecID:[77596687] SpecTime:{Start:1 End:2} Sort:1}
--- PASS: TestUnnewdecoder (0.00s)
PASS

总结

两种方法的区别

  1. json.NewDecoder是从一个流里面直接进行解码,代码精干;
  2. json.Unmarshal是从已存在与内存中的json进行解码;
  3. 相对于解码,json.NewEncoder进行大JSON的编码比json.marshal性能高,因为内部使用pool。

使用场景

  1. json.NewDecoder用于http连接与socket连接的读取与写入,或者文件读取;
  2. json.Unmarshal用于直接是byte的输入。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值