Go语言实现简单的反序列化

这段代码实现了一个简单的 JSON 序列化和反序列化功能。代码包括一个 User 结构体和两个函数 MarshalUnMarshal,分别用于将数据转换为 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 格式,支持通过标签来解析结构体字段。
  • main 函数:

    • 创建一个 User 对象,并将其序列化为 JSON。
    • 将序列化后的 JSON 字符串反序列化为新的 User 对象,并打印结果。
posted @ 2024-09-12 05:24  ffff5  阅读(49)  评论(0)    收藏  举报