Go语言中json使用

Go语言中JSON的使用

JSON 格式是一种用途广泛的对象文本格式。 Go 语言中, 结构体可以通过系统提供的 json.Marshal() 函数进行序列化。

1. 数据结构及入口函数

将结构体序列化为JSON的步骤如下:

a. 准备数据结构体

b. 准备要序列化的结构体数据

c. 调用序列化函数

参见下面的代码:

type ColorGroup struct {
	ID     int
	Name   string
	Colors []string
}

func marshalTest() {
    // 实例化结构体并初始化
	group := ColorGroup{
		ID:     1,
		Name:   "Reds",
		Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
	}
	b, err := json.Marshal(group) //调用json.Marshal序列化为字节数组
	if err != nil {
		fmt.Println("error:", err)
	}
	os.Stdout.Write(b)
	os.Stdout.WriteString("\n")
}
func main() {
    marshalTest()
}

输出内容如下:

{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}

2. 序列化主函数

MarshalJson()是序列化过程的主要函数入口,通过这个函数会调用不同类型的子序列化函数。

如下代码所示:

func MarshalJson(v interface{}) (string, error) {
	var b bytes.Buffer	//准备一个缓冲,在大量字符串连接时,推荐使用这个结构。
	if err := writeAny(&b, reflect.ValueOf(v)); err == nil {
		return b.String(), nil
	} else {
		return "", nil
	}
}

MarshalJson()这个函数其实是对 writeAny ()函数的一个封装,将外部的 interface{}类型转换为内部的 reflect. Value 类型,同时构建输出缓冲,将一些复杂的操作简化,方便外部使用。

3. 任意值序列化

writeAny()函数传入一字节缓冲和反射值对象,将反射值对象转换为 JSON 格式并写入字节缓冲中 。参见下面的代码

func writeAny(buff *bytes.Buffer, value reflect.Value) error {
	switch value.Kind() {
	case reflect.String:
		buff.WriteString(strconv.Quote(value.String()))
	case reflect.Int:
		buff.WriteString(strconv.FormatInt(value.Int(), 10))
	case reflect.Slice:
		return WriteSlice(buff, value)
	case reflect.Struct:
		return WriteStruct(buff, value)
	default:
		return errors.New("unsupport kind: " + value.Kind().String())
	}
	return nil
}

## 4. 切片序列化

writeAny()函数中会调用 writeSlice ()函数将切片类型转换为 JSON 格式的字符串并将数据写入缓冲中。参见下面的代码。

```go
// 将切片转为JSON格式并输出到缓冲中
func WriteSlice(buff *bytes.Buffer, value reflect.Value) error {
	buff.WriteString("[")              //写入切片开始标记
	for s := 0; s < value.Len(); s++ { // 遍历切片的元素
		sliceValue := value.Index(s)
		writeAny(buff, sliceValue)
		if s < value.Len()-1 { //每个元素尾部写入逗号,最后一个字段不添加
			buff.WriteString(",")
		}
	}
	buff.WriteString("]") //写入切片结束标记
	return nil
}

5. 结构体序列化

结构体由键值对组成,以大括号开始和结束。元素均以逗号分隔。序列化结构体的过程参见下面的代码。

// 将结构体序列化为JSON格式并输出到缓冲中
func WriteStruct(buff *bytes.Buffer, value reflect.Value) error {
	valueType := value.Type()
	buff.WriteString("{")                   //写入结构体左大括号
	for i := 0; i < value.NumField(); i++ { // 遍历结构体的元素
		fieldValue := value.Field(i)     //获取每个字段的字段值
		fieldType := valueType.Field(i)  //获取每个字段的类型
		buff.WriteString("\"")           //写入字段名左引号
		buff.WriteString(fieldType.Name) //写入字段名
		buff.WriteString("\":")          //写入字段名右引号和冒号
		writeAny(buff, fieldValue)       //写入字段值

		if i < value.NumField()-1 { //每个元素尾部写入逗号,最后一个字段不添加
			buff.WriteString(",")
		}
	}
	buff.WriteString("}") //写入结构体右大括号标记
	return nil
}

6. 总结

上面例子只支持整型、字符串、切片和结构体类型序列化为 JSON 格式。如果需要扩充类型,可以在 writeAny()函数中添加。程序功能和结构上还有些不足,例如:

  • 没有处理各种异常情况,切片或结构体为空时应该提前判断,否则会触发宕机

  • 可以支持结构体标签( Struct Tag ),方便 自定义 JSON 的键名及忽略某些字段的序列化过程,避免这些字段被序列化到 JSON

  • 支持缩进且可以自定义缩进字符,将 JSON 序列化后的内容格式化,方便查看。

  • 默认应该序列化为[]byte 字节数组外部自己转换为字符串。在大部分的使用中,JSON 一般 字节数组方式解析、存储、传输,很少以字符串方式解析,因此避免字节数组和字符串的转换可 以提高一些性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值