Go 自定义序列化
实现MarshalJSON() ([]byte, error)
方法 ,序列化后可以把原来的枚举数转化为枚举数对应的字符串
实现UnmarshalJSON([]byte) error
方法,可以把byte中的枚举的字符串转化为对应枚举字符串的枚举数
实现String() string
方法,方便按照我们想看的方式打印出来fmt.Println()
,类似与python的__str__
和__repr__
package main_test
import (
"errors"
"fmt"
"strings"
"testing"
"github.com/bytedance/sonic"
)
type A struct {
B B
C string
}
type B int8
const (
UP B = iota
DOWN
PENDING
)
var (
StatusValueMap = map[B]string{
UP: "up",
DOWN: "down",
PENDING: "pending",
}
)
//实现 MarshalJSON 对枚举值进行转化
func (b B) MarshalJSON() ([]byte, error) {
if v, ok := StatusValueMap[b]; ok {
return []byte(`"` + v + `"`), nil
}
return nil, errors.New("枚举未定义")
}
//实现 UnmarshalJSON 对枚举值进行转化
func (b *B) UnmarshalJSON(data []byte) error {
s := strings.Trim(string(data), `"`)
for k, v := range StatusValueMap {
if v == s {
b = &k
return nil
}
}
return errors.New("未转化成功")
}
//实现String方法,方便打印查看
func (b B) String() string {
return StatusValueMap[b]
}
func TestAbc(t *testing.T) {
a := A{
B: UP,
C: "111",
}
//json标准库和sonic第三方库都可以
// s, err := json.Marshal(a)
s, err := sonic.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(string(s)) //{"B":"up","C":"111"} 可以看到,已经将数字序列化成数字对应的字符串
b := &A{}
// err = json.Unmarshal(s, b)
err = sonic.Unmarshal(s, b)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", b) //&{B:up C:111} //已经将字符串反序列化为数字,这里显示up是因为实现了String()方法,可以看到,下面是等于0的
fmt.Println(b.B == 0) //true
}
遇到的坑
直接应用项为枚举时
如果结构体是如下这种
type A struct {
Title string `json:"title" gorm:"column:title;uniqueIndex:idx_title" validate:"required"`
Author string `json:"author" gorm:"column:author;not null" validate:"required"`
Summary string `json:"summary" gorm:"column:summary;not null"`
Content string `json:"content" gorm:"column:content"`
//这里省略了后面跟的Status,是可以正常使用的,但是如果实现了序列化的三个方法,会导致整个结构体只有status被序列化,其他的被忽略
Status `json:"status" gorm:"column:status;not null"`
}
// Status Status枚举
type Status int8
const (
DRAFT Status = 1 + iota
PUBLISHED
)
// 实现序列化的方法
//新建对应status序列化对应的字符串
var (
StatusValueMap = map[Status]string{
DRAFT: "DRAFT",
PUBLISHED: "PUBLISHED",
}
)
// 实现方法 MarshalJSON()、UnmarshalJSON()、String()
// 实现 MarshalJSON 对枚举值进行转化
func (sta Status) MarshalJSON() ([]byte, error) {
if v, ok := StatusValueMap[sta]; ok {
return []byte(`"` + v + `"`), nil
}
return nil, errors.New("枚举未定义")
}
// 实现 UnmarshalJSON 对枚举值进行转化
func (sta *Status) UnmarshalJSON(data []byte) error {
s := strings.Trim(string(data), `"`)
for k, v := range StatusValueMap {
if v == s {
sta = &k
return nil
}
}
return errors.New("未转化成功")
}
// 实现String方法,方便打印查看
func (sta Status) String() string {
return StatusValueMap[sta]
}
在A结构体中,继承了枚举Status的结构体
这个时候,如果Status实现了序列化的三个方法MarshalJSON()
、UnmarshalJSON()
、String()
则会导致结构体A序列化时,只显示Status序列化的值,而A中的其他项都不会被序列化
序列化
func main() {
a := &A{}
res, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(string(res))
}
/*
结果为
"DRAFT"
*/
显然这不是我们想要的
正确的继承方法是
type A struct {
Title string `json:"title" gorm:"column:title;uniqueIndex:idx_title" validate:"required"`
Author string `json:"author" gorm:"column:author;not null" validate:"required"`
Summary string `json:"summary" gorm:"column:summary;not null"`
Content string `json:"content" gorm:"column:content"`
//这里需要写清楚,不要省略第二个Status
Status Status `json:"status" gorm:"column:status;not null"`
}
// Status Status枚举
type Status int8
const (
DRAFT Status = 1 + iota
PUBLISHED
)
结果
{"title":"","author":"","summary":"","content":"","status":"DRAFT"}
不要省略Status后跟的Status
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/17034046.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具