注意:仅作为学习参考,并没有完整实现所有类型
type User struct {
Name string
Age int
Sex byte `json:"sex"`
}
type Book struct {
ISBN string `json:"isbn"`
Name string
Price float32 `json:"price"`
Author *User `json:"author"`
Keywords []string `json:"keywords"`
Local map[int]bool // TODO 暂不支持map
}
func main() {
user := User{
Name: "钱钟书",
Age: 57,
Sex: 1,
}
book := Book{
ISBN: "4243547567",
Name: "围城",
Price: 34.8,
Author: &user,
Keywords: []string{"爱情", "民国", "留学"},
Local: map[int]bool{2: true, 3: false},
}
if bytes, err := Marshal(book); err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(string(bytes))
var b Book
if err = Unmarshal(bytes, &b); err != nil {
fmt.Println(err.Error())
}
fmt.Println(b)
}
}
func Marshal(v interface{}) ([]byte, error) {
value := reflect.ValueOf(v)
typ := value.Type() // 跟typ := reflect.TypeOf(v)等价
if typ.Kind() == reflect.Ptr {
if value.IsNil() { // 如果指向nil, 直接输出null
return []byte("null"), nil
} else { // 如果传的是指针类型,先解析指针
typ = typ.Elem()
value = value.Elem()
}
}
bf := bytes.Buffer{} // 存放序列化结果
switch typ.Kind() {
case reflect.String:
return []byte(fmt.Sprintf("\"%s\"", value.String())), nil
case reflect.Bool:
return []byte(fmt.Sprintf("%t", value.Bool())), nil
case reflect.Float32,
reflect.Float64:
return []byte(fmt.Sprintf("%f", value.Float())), nil
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64,
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
return []byte(fmt.Sprintf("%v", value.Interface())), nil
case reflect.Slice:
if value.IsNil() {
return []byte("null"), nil
}
bf.WriteByte('[')
if value.Len() > 0 {
for i := 0; i < value.Len(); i++ { // 去的slice的长度
if bs, err := Marshal(value.Index(i).Interface()); err != nil { // 对slice的第i个元素进行序列化,递归
return nil, err
} else {
bf.Write(bs)
bf.WriteByte(',')
}
}
bf.Truncate(len(bf.Bytes()) - 1) // 删除最后一个逗号
}
bf.WriteByte(']')
return bf.Bytes(), nil
case reflect.Struct:
bf.WriteByte('{')
if value.NumField() > 0 {
for i := 0; i < value.NumField(); i++ {
fieldValue := value.Field(i)
fieldType := typ.Field(i)
name := fieldType.Name // 如果没有json tag, 默认使用成员变量的名称
if len(fieldType.Tag.Get("json")) > 0 {
name = fieldType.Tag.Get("json")
}
bf.WriteString("\"")
bf.WriteString(name)
bf.WriteString("\"")
bf.WriteString(":")
if bs, err := Marshal(fieldValue.Interface()); err != nil {
return nil, err
} else {
bf.Write(bs)
}
bf.WriteString(",")
}
bf.Truncate(len(bf.Bytes()) - 1)
}
bf.WriteByte('}')
return bf.Bytes(), nil
default:
return []byte(fmt.Sprintf("\"暂不支持该数据类型:%s\"", typ.Kind().String())), nil
}
}
func Unmarshal(data []byte, v interface{}) error {
s := string(data)
// 去除前后的连续空格
s = strings.TrimLeft(s, " ")
s = strings.TrimRight(s, " ")
if len(s) == 0 {
return nil
}
typ := reflect.TypeOf(v)
value := reflect.ValueOf(v)
if typ.Kind() != reflect.Ptr { // 因为要修改v,必须传指针
return errors.New("must pass pointer parameter")
}
typ = typ.Elem() // 解析指针
value = value.Elem()
switch typ.Kind() {
case reflect.String:
if s[0] == '"' && s[len(s)-1] == '"' {
value.SetString(s[1 : len(s)-1])
} else {
return fmt.Errorf("invalid json part: %s", s)
}
case reflect.Bool:
if b, err := strconv.ParseBool(s); err != nil {
return err
} else {
value.SetBool(b)
}
case reflect.Float32,
reflect.Float64:
if f, err := strconv.ParseFloat(s, 64); err != nil {
return err
} else {
value.SetFloat(f)
}
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
if i, err := strconv.ParseInt(s, 10, 64); err != nil {
return err
} else {
value.SetInt(i)
}
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
if i, err := strconv.ParseUint(s, 10, 64); err != nil {
return err
} else {
value.SetUint(i)
}
case reflect.Slice:
if s[0] == '[' && s[len(s)-1] == ']' {
arr := SplitJson(s[1 : len(s)-1]) // 取出前后的[]
if len(arr) > 0 {
slice := reflect.ValueOf(v).Elem() // v 是指针
slice.Set(reflect.MakeSlice(typ, len(arr), len(arr))) // 通过反射创建slice
for i := 0; i < len(arr); i++ {
eleValue := slice.Index(i)
eleType := eleValue.Type()
if eleType.Kind() != reflect.Ptr {
eleValue = eleValue.Addr() // 转换成指针
}
if err := Unmarshal([]byte(arr[i]), eleValue.Interface()); err != nil {
return err
}
}
}
} else if s != "null" {
return fmt.Errorf("invalid json part: %s", s)
}
case reflect.Struct:
if s[0] == '{' && s[len(s)-1] == '}' {
arr := SplitJson(s[1 : len(s)-1])
if len(arr) > 0 {
fieldCount := typ.NumField()
// 建立json tag 到fieldName映射关系
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 {
name = fieldType.Tag.Get("json")
}
tag2Field[name] = fieldType.Name
}
for _, ele := range arr {
//json的value里可能存在嵌套, 所以用:分隔时指定个数为2
brr := strings.SplitN(ele, ":", 2)
if len(brr) == 2 {
tag := strings.Trim(brr[0], " ")
// json 的key肯定是带""的
if tag[0] == '"' && tag[len(tag)-1] == '"' {
// 去掉jsonkey前后的""
tag = tag[1 : len(tag)-1]
// 根据json key(即json tag)找到对应的fieldName
if fieldName, exists := tag2Field[tag]; exists {
fieldValue := value.FieldByName(fieldName)
fieldType := fieldValue.Type()
if fieldType.Kind() != reflect.Ptr {
// 如果内嵌不是指针,则声明已经用0值初始化了,此处只需要根据json该写它的值
fieldValue = fieldValue.Addr() // 转成指针
if err := Unmarshal([]byte(brr[1]), fieldValue.Interface()); err != nil {
return err
}
} else {
// 如果内嵌的是指针,则需要通过New()创建一个实例(申请内存空间)。不能给New()传指针烈性的Type
newValue := reflect.New(fieldType.Elem())
if err := Unmarshal([]byte(brr[1]), newValue.Interface()); err != nil {
return err
}
value.FieldByName(fieldName).Set(newValue) // 把newValue赋给value的field
}
} else {
fmt.Printf("字段%s找不到\n", tag)
}
} else {
return fmt.Errorf("invalid json part: %s", tag)
}
} else {
return fmt.Errorf("invalid json part: %s", ele)
}
}
}
} else if s != "null" {
return fmt.Errorf("invalid json part: %s", s)
}
default:
return fmt.Errorf("暂不支持类型:%s\n", typ.Kind().String())
}
return nil
}
// SplitJson 由于json字符串里存在{}[]等嵌套情况,直接按,分隔是不合适的
func SplitJson(json string) []string {
rect := make([]string, 0, 10)
stack := list.New() // list是双端度列,用它来模拟栈
beginIndex := 0
for i, r := range json {
if r == rune('{') || r == rune('[') {
stack.PushBack(struct{}{}) // 我们不关心栈里面是什么,只关心栈里有没有元素
} else if r == rune('}') || r == rune(']') {
ele := stack.Back()
if ele != nil {
stack.Remove(ele)
}
} else if r == rune(',') {
if stack.Len() == 0 {
rect = append(rect, json[beginIndex:i])
beginIndex = i + 1
}
}
}
rect = append(rect, json[beginIndex:])
return rect
}