Loading [MathJax]/extensions/MathMenu.js

我在上一篇文章详细介绍了go反射的API用法,参见 一篇带你全面掌握go反射的用法 - 张朝阳 - 博客园 (cnblogs.com)

go自带的json序列化就是通过反射来实现的,为了加深对反射API的掌握程度,我自动实现了类似json序列化和反序列化功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
package main
 
import (
    "bytes"
    "container/list"
    "encoding/json"
    "errors"
    "fmt"
    "reflect"
    "strconv"
    "strings"
)
 
type User struct {
    Name string
    Age  int
    Sex  byte `json:"gender"`
}
 
type Book struct {
    ISBN     string `json:"isbn"`
    Name     string
    Price    float32      `json:"price"`
    Author   *User        `json:"author"` //把指针去掉试试
    Keywords []string     `json:"kws"`
    Local    map[int]bool //TODO 暂不支持map
}
 
//由于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
}
 
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 //取得reflect.Value对应的原始数据的值
    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.Map:
        if value.IsNil() {
            return []byte("null"), nil
        }
        bf.WriteByte('{')
        if value.Len() > 0 {
            for _, key := range value.MapKeys() {
                if keyBs, err := Marshal(key.Interface()); err != nil {
                    return nil, err
                } else {
                    bf.Write(keyBs)
                    bf.WriteByte(':')
                    v := value.MapIndex(key)
                    if vBs, err := Marshal(v.Interface()); err != nil {
                        return nil, err
                    } else {
                        bf.Write(vBs)
                        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 { //对value递归调用Marshal序列化
                    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 {
            value.SetBool(b)
        } else {
            return err
        }
    case reflect.Float32,
        reflect.Float64:
        if f, err := strconv.ParseFloat(s, 64); err != nil {
            return err
        } else {
            value.SetFloat(f) //通过reflect.Value修改原始数据的值
        }
    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) //有符号整型通过SetInt
        }
    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) //无符号整型需要通过SetUint
        }
    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.Map:
        if s[0] == '{' && s[len(s)-1] == '}' {
            arr := SplitJson(s[1 : len(s)-1]) //去除前后的{}
            if len(arr) > 0 {
                mapValue := reflect.ValueOf(v).Elem()                //别忘了,v是指针
                mapValue.Set(reflect.MakeMapWithSize(typ, len(arr))) //通过反射创建map
                kType := typ.Key()                                   //获取map的key的Type
                vType := typ.Elem()                                  //获取map的value的Type
                for i := 0; i < len(arr); i++ {
                    brr := strings.Split(arr[i], ":")
                    if len(brr) != 2 {
                        return fmt.Errorf("invalid json part: %s", arr[i])
                    }
 
                    kValue := reflect.New(kType) //根据Type创建指针型的Value
                    if err := Unmarshal([]byte(brr[0]), kValue.Interface()); err != nil {
                        return err
                    }
                    vValue := reflect.New(vType) //根据Type创建指针型的Value
                    if err := Unmarshal([]byte(brr[1]), vValue.Interface()); err != nil {
                        return err
                    }
                    mapValue.SetMapIndex(kValue.Elem(), vValue.Elem()) //往map里面赋值
                }
            }
        } 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 {
                    brr := strings.SplitN(ele, ":", 2) //json的value里可能存在嵌套,所以用:分隔时限定个数为2
                    if len(brr) == 2 {
                        tag := strings.Trim(brr[0], " ")
                        if tag[0] == '"' && tag[len(tag)-1] == '"' { //json的key肯定是带""的
                            tag = tag[1 : len(tag)-1]                        //去除json key前后的""
                            if fieldName, exists := tag2Field[tag]; exists { //根据json key(即json tag)找到对应的FieldName
                                fieldValue := value.FieldByName(fieldName)
                                fieldType := fieldValue.Type()
                                if fieldType.Kind() != reflect.Ptr {
                                    //如果内嵌不是指针,则声明时已经用0值初始化了,此处只需要根据json改写它的值
                                    fieldValue = fieldValue.Addr()                                            //确保fieldValue指向指针类型,因为接下来要把fieldValue传给Unmarshal
                                    if err := Unmarshal([]byte(brr[1]), fieldValue.Interface()); err != nil { //递归调用Unmarshal,给fieldValue的底层数据赋值
                                        return err
                                    }
                                } else {
                                    //如果内嵌的是指针,则需要通过New()创建一个实例(申请内存空间)。不能给New()传指针型的Type,所以调一下Elem()
                                    newValue := reflect.New(fieldType.Elem())                               //newValue代表的是指针
                                    if err := Unmarshal([]byte(brr[1]), newValue.Interface()); err != nil { //递归调用Unmarshal,给fieldValue的底层数据赋值
                                        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:
        fmt.Printf("暂不支持类型:%s\n", typ.Kind().String())
    }
    return nil
}
 
func main() {
    user := User{
        Name: "钱钟书",
        Age:  57,
        Sex:  1,
    }
    book := Book{
        ISBN:     "4243547567",
        Name:     "围城",
        Price:    34.8,
        Author:   &user,                      //改成nil试试
        Keywords: []string{"爱情", "民国", "留学"}, //把这一行注释掉试一下,测测null
        Local:    map[int]bool{2: true, 3: false},
    }
 
    if bytes, err := Marshal(user); err != nil { //也可以给Marshal传指针类型
        fmt.Printf("序列化失败: %v\n", err)
    } else {
        fmt.Println(string(bytes))
        var u User
        if err = Unmarshal(bytes, &u); err != nil {
            fmt.Printf("反序列化失败: %v\n", err)
        } else {
            fmt.Printf("user name %s\n", u.Name)
        }
    }
 
    if bytes, err := json.Marshal(user); err != nil {
        fmt.Printf("序列化失败: %v\n", err)
    } else {
        fmt.Println(string(bytes))
        var u User
        if err = json.Unmarshal(bytes, &u); err != nil {
            fmt.Printf("反序列化失败: %v\n", err)
        } else {
            fmt.Printf("user name %s\n", u.Name)
        }
    }
 
    if bytes, err := Marshal(book); err != nil { //也可以给Marshal传指针类型
        fmt.Printf("序列化失败: %v\n", err)
    } else {
        fmt.Println(string(bytes))
        var b Book //必须先声明值类型,再通过&给Unmarshal传一个指针参数。因为声明值类型会初始化为0值,而声明指针都没有创建底层的内存空间
        if err = Unmarshal(bytes, &b); err != nil {
            fmt.Printf("反序列化失败: %v\n", err)
        } else {
            fmt.Printf("book name %s author name %s local %v\n", b.Name, b.Author.Name, b.Local)
        }
    }
 
    if bytes, err := json.Marshal(book); err != nil {
        fmt.Printf("序列化失败: %v\n", err)
    } else {
        fmt.Println(string(bytes))
        var b Book
        if err = json.Unmarshal(bytes, &b); err != nil {
            fmt.Printf("反序列化失败: %v\n", err)
        } else {
            fmt.Printf("book name %s author name %s local %v\n", b.Name, b.Author.Name, b.Local)
        }
    }
}

  

posted on   高性能golang  阅读(565)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决
点击右上角即可分享
微信分享提示