Let‘s Go —— Go语言开发之旅(五)

json对象序列化支持包开发

概述

将一个对象写成特定文本格式的字符流,称为序列化。

什么是json

JSON简单的理解就是特殊格式的字符串,被设计用来传输和存储数据,和xml类似,但是在API和前后端分离数据交互更多是使用json,json不仅比XML简单,传输中更节省文本。网站中的ajax、后端api基本上是使用json编码后的数据。

基本规则

  • 只有合法的json串才能解析(废话)
    key只能是string;
    map的形式必须是map[string]T,T是Go的基本类型;
    Channel, complex, function 不能进行编码;
    循环数据不支持;
    指针会被编码成指针的值,nil是null。
    
  • 只有可导出(exported)的字段才能解析
    即首字符大写的字段才能显示在json对象中,解析规则有如下顺序,例如一个key:Foo
    1.先找tag是Foo的
    2.找字段名是Foo的
    3.找FOO或者FoO等
    

核心功能

参考官方 encoding/json 包 Marshal 函数,将结构数据格式化为 json 字符流

  • 导出 func JsonMarshal(v interface{}) ([]byte, error)
  • 支持字段的标签(Tag),标签满足 mytag:“你自己的定义”

输出格式

首先需要设定读取后输出的json格式

const (
	jsonTag              = "json"
	jsonStart            = "{"
	jsonEnd              = "}"
	arrayStart           = "["
	arrayEnd             = "]"
	stringStartEnd       = `"`
	stringStartEndScaped = ``
	is                   = `:`
	comma                = ","
	null                 = "null"
	empty                = " "
	booleanTrue          = "true"
	booleanFalse         = "false"
)

读取结果

将从结构体读取的结果存储到marshal结构体中

type marshal struct {
	object interface{}
	result *bytes.Buffer
	tags   []string
}

json对象序列化

通过下列函数完成json对象序列化的功能

func (m *marshal) getValue(value reflect.Value) (reflect.Value, reflect.Type, error)
func (m *marshal) do(object reflect.Value) error
func (m *marshal) handleKey(key reflect.Value) error
func (m *marshal) handleValue(object reflect.Value) error
func (m *marshal) handleMarshalJSON(object reflect.Value) (bool, []byte, error)
func (m *marshal) loadTag(typ reflect.StructField) (exists bool, tag string, err error)
func (m *marshal) encodeString(str string) string

JsonMarshal

最后导出JsonMarshal接口

func (m *marshal) execute() ([]byte, error) {
	err := m.do(reflect.ValueOf(m.object))
	return m.result.Bytes(), err
}

func JsonMarshal(object interface{}, tags ...string) ([]byte, error) {
	return newMarshal(object, tags...).execute()
}

单元测试

为了验证JsonMarshal json对象序列化的准确性,我们设置了两个单元测试

func TestMarshal1(t *testing.T) {

    	expected := `{"name":"joao","age":30,"address":{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"numbers":[1,2,3],"others":{"ola joao":{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"c":{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}},"addresses":[{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}]}`

	addr := &address{
		Street: "street one",
		Number: 1.2,
		Map:    map[string]string{`"ola" "joao"`: `"adeus" "joao"`, "c": "d"},
	}

	example := person{
		Name:      "joao",
		Age:       30,
		Address:   addr,
		Numbers:   []int{1, 2, 3},
		Others:    map[string]*address{`"ola" "joao"`: addr, "c": addr},
		Addresses: []*address{addr, addr},
	}

	// with tags "db" and "db.write"
	// marshal
	bytes, err := JsonMarshal(example, "db", "db.write")
	if err != nil {
		panic(err)
	}

    	res := string(bytes)

    	if res != expected {
        	t.Errorf("expected '%q' but got '%q'", expected, res)
    	}
}
func TestMarshal2(t *testing.T) {

    	expected := `{"name":"joao","age":30,"address":{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"numbers":[1,2,3],"others":{"ola joao":{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"c":{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}},"addresses":[{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}]}`

	addr := &address{
		Street: "street one",
		Number: 1.2,
		Map:    map[string]string{`"ola" "joao"`: `"adeus" "joao"`, "c": "d"},
	}

	example := person{
		Name:      "joao",
		Age:       30,
		Address:   addr,
		Numbers:   []int{1, 2, 3},
		Others:    map[string]*address{`"ola" "joao"`: addr, "c": addr},
		Addresses: []*address{addr, addr},
	}

	// with tags "db" and "db.read"
	// marshal
	bytes2, err := JsonMarshal(example, "db", "db.read")
	if err != nil {
		panic(err)
	}

    	res := string(bytes2)

    	if res != expected {
        	t.Errorf("expected '%q' but got '%q'", expected, res)
    	}
}

运行测试结果如下
在这里插入图片描述

参考资料

程序包开发-Json格式序列化
encoding/json

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值