Go语言实现简单的反序列化
这段代码实现了一个简单的 JSON 序列化和反序列化功能。代码包括一个 User 结构体和两个函数 Marshal 和 UnMarshal,分别用于将数据转换为 JSON 格式和将 JSON 格式的数据解析回结构体。
package main
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
)
// User 定义了一个用户结构体,其中包含名称、年龄和性别字段
type User struct {
Name string
Age string
Sex byte `json:"gender"` // 使用 json 标签自定义字段名
}
// Marshal 将任意类型 v 序列化为 JSON 格式的字节数组
func Marshal(v interface{}) ([]byte, error) {
value := reflect.ValueOf(v) // 获取值的反射对象
typ := value.Type() // 获取值的类型
bf := bytes.Buffer{} // 使用 bytes.Buffer 以高效地构造 JSON 字符串
switch typ.Kind() {
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64, reflect.Uint8:
// 对于整数类型,将其转换为字符串并返回字节数组
return []byte(fmt.Sprintf("%v", value.Interface())), nil
case reflect.String:
// 对于字符串类型,将其加上双引号后返回字节数组
return []byte("\"" + value.String() + "\""), nil
case reflect.Bool:
// 对于布尔值,将其转换为 "true" 或 "false" 字符串
return []byte(fmt.Sprintf("%t", value.Bool())), nil
case reflect.Float32, reflect.Float64:
// 对于浮点数类型,将其转换为字符串并返回字节数组
return []byte(fmt.Sprintf("%f", value.Float())), nil
case reflect.Struct:
// 对于结构体类型,构造 JSON 格式的字符串
bf.WriteByte('{')
if value.NumField() > 0 {
for i := 0; i < value.NumField(); i++ {
fieldValue := value.Field(i) // 获取字段值
fieldType := typ.Field(i) // 获取字段类型
if fieldType.IsExported() {
// 处理导出字段
name := fieldType.Name
if len(fieldType.Tag.Get("json")) > 0 {
// 使用 JSON 标签指定的字段名
name = fieldType.Tag.Get("json")
}
bf.WriteByte('"')
bf.WriteString(name)
bf.WriteByte('"')
bf.WriteByte(':')
if bs, err := Marshal(fieldValue.Interface()); err == nil {
bf.Write(bs)
} else {
return nil, err
}
bf.WriteByte(',')
}
}
bf.Truncate(len(bf.Bytes()) - 1) // 删除最后一个逗号
}
bf.WriteByte('}')
return bf.Bytes(), nil
default:
// 对于不支持的类型,返回错误
return nil, fmt.Errorf("暂不支持该类型%s", typ.Kind())
}
}
// UnMarshal 将 JSON 格式的字节数组 data 解析为类型为 v 的值
func UnMarshal(v interface{}, data []byte) error {
value := reflect.ValueOf(v) // 获取值的反射对象
typ := value.Type() // 获取值的类型
if typ.Kind() != reflect.Ptr {
return fmt.Errorf("必须为指针")
} else {
typ = typ.Elem() // 获取指针指向的类型
value = value.Elem() // 获取指针指向的值
}
s := string(data) // 将字节数组转换为字符串
switch typ.Kind() {
case reflect.Int:
// 解析整数
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
value.SetInt(i) // 设置解析后的整数值
} else {
return err
}
case reflect.Uint8:
// 解析无符号整数(字节)
if i, err := strconv.ParseUint(s, 10, 64); err == nil {
value.SetUint(i) // 设置解析后的字节值
} else {
return err
}
case reflect.Bool:
// 解析布尔值
if b, err := strconv.ParseBool(s); err == nil {
value.SetBool(b) // 设置解析后的布尔值
} else {
return err
}
case reflect.Float32:
// 解析浮点数
if f, err := strconv.ParseFloat(s, 64); err == nil {
value.SetFloat(f) // 设置解析后的浮点数值
} else {
return err
}
case reflect.String:
// 解析字符串,确保字符串被双引号包围
if s[0] == '"' && s[len(s)-1] == '"' {
value.SetString(s[1 : len(s)-1]) // 去掉双引号
} else {
return fmt.Errorf("json格式不对")
}
case reflect.Struct:
// 解析结构体
if s[0] == '{' && s[len(s)-1] == '}' {
arr := strings.Split(s[1:len(s)-1], ",") // 去掉大括号并拆分字段
if len(arr) > 0 {
fieldCount := typ.NumField()
tag2Field := make(map[string]string, fieldCount)
for i := 0; i < fieldCount; i++ {
fieldType := typ.Field(i)
name := fieldType.Name
if len(fieldType.Tag.Get("json")) > 0 {
// 使用 JSON 标签指定的字段名
name = fieldType.Tag.Get("json")
}
tag2Field[name] = fieldType.Name
}
for _, ele := range arr {
brr := strings.SplitN(ele, ":", 2) // 拆分标签和数据
tag := brr[0]
if tag[0] == '"' && tag[len(tag)-1] == '"' {
tag = tag[1 : len(tag)-1]
if fieldName, exists := tag2Field[tag]; exists {
fieldValue := value.FieldByName(fieldName)
fieldType := fieldValue.Type()
if fieldValue.Kind() != reflect.Ptr {
fieldValue = fieldValue.Addr()
if err := UnMarshal(fieldValue.Interface(), []byte(brr[1])); err != nil {
return err
}
} else {
newValue := reflect.New(fieldType.Elem())
if err := UnMarshal(newValue.Interface(), []byte(brr[1])); err != nil {
return err
} else {
fieldValue.Set(newValue)
}
}
}
} else {
return fmt.Errorf("json格式不对%s", tag)
}
}
}
} else {
return fmt.Errorf("格式错误")
}
default:
// 对于不支持的类型,返回错误
return fmt.Errorf("暂不支持该数据类型%s", typ.Kind())
}
return nil
}
// main 函数演示了如何使用 Marshal 和 UnMarshal 函数
func main() {
user := User{
Name: "ffff5",
Age: "35",
Sex: 1,
}
if date, err := Marshal(user); err == nil {
fmt.Println(string(date)) // 打印序列化后的 JSON 字符串
var u2 = user
if err := UnMarshal(&u2, date); err == nil {
fmt.Println(u2.Name, u2.Age, u2.Sex) // 打印反序列化后的数据
} else {
fmt.Println(err) // 打印错误信息
}
} else {
fmt.Println(err) // 打印序列化错误
}
}
-
User结构体:- 定义了一个包含
Name(名称)、Age(年龄)和Sex(性别)字段的结构体。 Sex字段使用了json标签来指定 JSON 中的字段名为"gender"。
- 定义了一个包含
-
Marshal函数:- 将传入的任意类型的值转换为 JSON 格式的字节数组。
- 支持整数、字符串、布尔值、浮点数和结构体。
- 对于结构体,处理字段标签和序列化字段值。
-
UnMarshal函数:- 将 JSON 格式的字节数组解析为传入指针类型
v所指向的值。 - 支持整数、字节(无符号 8 位整数)、布尔值、浮点数、字符串和结构体。
- 处理 JSON 格式,支持通过标签来解析结构体字段。
- 将 JSON 格式的字节数组解析为传入指针类型
-
main函数:- 创建一个
User对象,并将其序列化为 JSON。 - 将序列化后的 JSON 字符串反序列化为新的
User对象,并打印结果。
- 创建一个
本文来自博客园,作者:ffff5,转载请注明原文链接:https://www.cnblogs.com/ffff5/p/18409387

浙公网安备 33010602011771号