我在上一篇文章详细介绍了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) } } } |
本文来自博客园,作者:高性能golang,转载请注明原文链接:https://www.cnblogs.com/zhangchaoyang/p/15441156.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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 重磅开源!
· 字符编码:从基础到乱码解决