无需修改Go结构体,实现int64/uint64与JS字符串的JSON互转
答案
可以实现,无需修改原有结构体定义或字段标签,推荐使用兼容标准库API的高性能JSON库json-iterator/go实现,无需侵入业务结构体,全局生效,实现成本最低。
实现步骤
- 安装依赖
go get github.com/json-iterator/go
- 全局注册int64、uint64类型的自定义编解码规则,完整代码示例如下:
package main import ( "fmt" "reflect" "strconv" "unsafe" jsoniter "github.com/json-iterator/go" ) type Foo struct { A int64 B uint64 // 其他包含int64、uint64字段的结构体无需做任何修改 } // 初始化阶段注册自定义编解码器,全局生效 func init() { int64Type := reflect.TypeOf(int64(0)).String() uint64Type := reflect.TypeOf(uint64(0)).String() // 注册int64序列化/反序列化规则 jsoniter.RegisterTypeEncoder(int64Type, &int64AsStringEncoder{}) jsoniter.RegisterTypeDecoder(int64Type, &int64AsStringDecoder{}) // 注册uint64序列化/反序列化规则 jsoniter.RegisterTypeEncoder(uint64Type, &uint64AsStringEncoder{}) jsoniter.RegisterTypeDecoder(uint64Type, &uint64AsStringDecoder{}) } // int64转JSON字符串序列化器 type int64AsStringEncoder struct{} func (e *int64AsStringEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { stream.WriteString(strconv.FormatInt(*(*int64)(ptr), 10)) } func (e *int64AsStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { return *(*int64)(ptr) == 0 } // JSON字符串/数值转int64反序列化器 type int64AsStringDecoder struct{} func (d *int64AsStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { switch iter.WhatIsNext() { case jsoniter.StringValue: val, err := strconv.ParseInt(iter.ReadString(), 10, 64) if err != nil { iter.ReportError("parse int64", err.Error()) return } *(*int64)(ptr) = val case jsoniter.NumberValue: *(*int64)(ptr) = iter.ReadInt64() default: iter.ReportError("parse int64", "unexpected value type") } } // uint64转JSON字符串序列化器 type uint64AsStringEncoder struct{} func (e *uint64AsStringEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { stream.WriteString(strconv.FormatUint(*(*uint64)(ptr), 10)) } func (e *uint64AsStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { return *(*uint64)(ptr) == 0 } // JSON字符串/数值转uint64反序列化器 type uint64AsStringDecoder struct{} func (d *uint64AsStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { switch iter.WhatIsNext() { case jsoniter.StringValue: val, err := strconv.ParseUint(iter.ReadString(), 10, 64) if err != nil { iter.ReportError("parse uint64", err.Error()) return } *(*uint64)(ptr) = val case jsoniter.NumberValue: *(*uint64)(ptr) = iter.ReadUint64() default: iter.ReportError("parse uint64", "unexpected value type") } } func main() { x := Foo{A: 1234567890987654, B: 987654321012345678} // 序列化,输出的int64/uint64自动带引号 byt, err := jsoniter.Marshal(x) fmt.Println(err) // <nil> fmt.Println(string(byt)) // {"A":"1234567890987654","B":"987654321012345678"} // 反序列化,自动解析带引号的数值为对应int64/uint64类型 err = jsoniter.Unmarshal([]byte(`{"A":"12345678901234567", "B":"98765432101234567"}`), &x) fmt.Println(err) // <nil> fmt.Printf("%#v\n", x) // main.Foo{A:12345678901234567, B:98765432101234567} }
标准库实现方案
如果不想引入第三方依赖,可以基于标准库encoding/json封装自定义的Marshal/Unmarshal函数,通过反射遍历结构体所有字段,对int64、uint64类型做特殊转换处理即可,缺点是性能略低于第三方库实现,适合对性能要求不高的场景。
内容的提问来源于stack exchange,提问作者Kokizzu
相关产品推荐
相关产品推荐

