首页 > 其他分享 >Go / Golang JSON 一些心得

Go / Golang JSON 一些心得

时间:2023-08-07 18:46:56浏览次数:47  
标签:string 自定义 json Golang JSON func Go 序列化 struct

自定义序列化和反序列化

可以实现 json.Marshaler 和 json.Unmarshaler 自定义json的序列化和反序列化

type Tags []string

func (t Tags) MarshalJSON() ([]byte, error) {
    return []byte(strconv.Quote(strings.Join(t, ","))), nil
}

func (t *Tags) UnmarshalJSON(b []byte) error {
    b = bytes.Trim(b, `"`)
    *t = strings.Split(string(b), ",")
    return nil
}

func TestTags(t *testing.T) {
    tags := Tags([]string{"美丽", "性感", "迷人"})
    b, _ := json.Marshal(tags)
    if `"美丽,性感,迷人"` != string(b) {
        t.Error("自定义序列化出错")
    }
    json.Unmarshal([]byte(`"性感,美丽,迷人"`), &tags)
    if tags[0] != "性感" || tags[1] != "美丽" || tags[2] != "迷人" {
        t.Error("自定义反序列化出错")
    }
}  

struct 的 tag

go结构体的字段经常用tag来扩展功能,比如json,我们也可以利用reflect包自定义tag解析(gorm利用结构体tag声明字段和数据库的映射)

type Product struct {
    Name     string  // 不写json tag,默认映射为Name
    RealName string  `json:"-"`               // 表示不序列化,也不反序列化
    Price    float64 `json:"price,string"`    // string 可以把 "16.56" 映射为 float64,会把 13.56 输出为 "13.56"
    Count    int     `json:"count,omitempty"` // omitempty 表示零值不输出
}

func TestProduct(t *testing.T) {
    p1 := Product{
        Name:     "iPhone",
        RealName: "iPhone 8 Pro",
        Price:    13.15,
        Count:    0,
    }
    b, _ := json.Marshal(&p1)
    if `{"Name":"iPhone","price":"13.15"}` != string(b) {
        t.Error("Product 序列化失败")
    }
}

不序列化 time.Time

使用time.Time nil指针表示不序列化json,防止输出非法格式的时间

func TestIgnoreNilTime(t *testing.T) {
    // 使用nil表示不输出时间
    user1 := struct {
        UserId    int        `json:"userId"`
        CreatedAt *time.Time `json:"createdAt,omitempty"`
    }{
        UserId: 100019,
    }
    b, _ := json.Marshal(&user1)
    if `{"userId":100019}` != string(b) {
        t.Error("")
    }
}

忽略字段和格式化字段

type User struct {
    UserId   int     `json:"userId"`
    Phone    string  `json:"phone"`
    Password string  `json:"password"`
    Money    float64 `json:"money"`
}

func TestStructEmbedded(t *testing.T) {
    user1 := User{
        UserId:   100019,
        Phone:    "13112120001",
        Password: "abc123",
        Money:    123.56123,
    }
    user2 := struct {
        User // 嵌入 User 结构
        Phone    string `json:"phone"` // 覆盖 User 结构中的 Phone 实现隐藏手机号
        Password string `json:"password,omitempty"` // 不输出密码
        Money    string `json:"money"` // 会覆盖 User 结构中的 Money
    }{
        User:  user1,
        Phone: filterPhone(user1.Phone),
        Money: fmt.Sprintf("%.2f", user1.Money),
    }
    b, _ := json.Marshal(&user2)
    if `{"userId":100019,"phone":"131****0001","money":"123.56"}` != string(b) {
        t.Error("")
    }
}

func filterPhone(phone string) string {
    if len(phone) != 11 {
        return ""
    }
    return phone[:3] + "****" + phone[7:]
}

结构体嵌入用来共用一些通用字段

结构体复制

简单结构使用手动复制就可以,复杂结构可用开源库来复制
比如 https://github.com/jinzhu/copier

结构体复制时,防止浅拷贝问题

结构体直接复制时,里面的指针或者slice等会指向同一份内存数据,修改时需要注意。
可以采用 [https://github.com/jinzhu/copier]https://github.com/jinzhu/copier 进行深拷贝

结构体嵌入和 json 自定义一起使用,可以在序列化和反序列化时做转换

type UserProfile struct {
    Nickname string `json:"nickname"`
    IdCardNo string `json:"idCardNo"`
}

func (u UserProfile) MarshalJSON() ([]byte, error) {
    type UserProfileAlias UserProfile
    u1 := struct {
        UserProfileAlias
        IdCardNo string `json:"idCardNo"`
    }{
        UserProfileAlias: UserProfileAlias(u),
        IdCardNo:         "****",
    }

    b, _ := json.Marshal(&u1)
    return b, nil
}

type Liver struct {
    UserProfile *UserProfile `json:"userProfile"`
}

func TestLiverJson(t *testing.T) {
    liver := Liver{
        UserProfile: &UserProfile{
            Nickname: "娜娜丫头",
            IdCardNo: "123456",
        },
    }
    b, _ := json.Marshal(&liver)
    if `{"userProfile":{"nickname":"娜娜丫头","idCardNo":"****"}}` != string(b) {
        t.Error("结构体嵌入和json自定义出错")
    }
}

标签:string,自定义,json,Golang,JSON,func,Go,序列化,struct
From: https://www.cnblogs.com/goallin/p/17612418.html

相关文章

  • MySQL和MongoDB如何JOIN查询?一个直接在本地运行的SQL执行引擎
    在微服务和云原生愈发流行的今天,数据的分布也愈发脱离单库单机而更加复杂,使用的数据库类型也会更多,但业务的复杂依然会带来了大量的数据查询和导出需求,而很多时候我们很难为数据量的大部分系统创建完整的BI数仓系统,这时候你是不是觉得为这些需求查询和导出数据就会是一个十分困难且......
  • 2023年8月最新全国省市区县和乡镇街道行政区划矢量边界坐标经纬度地图数据 shp geojso
    发现个可以免费下载全国 geojson 数据的网站,推荐一下。支持全国、省级、市级、区/县级、街道/乡镇级以及各级的联动数据,支持导入矢量地图渲染框架中使用,例如:D3、Echarts等geojson数据下载地址:https://geojson.hxkj.vip该项目github地址:https://github.com/TangSY/echarts-m......
  • django模板使用的总结(2)
    项目模板使用分析模板总结1,主要讲了一些原理和使用方法。现在开始在项目上进行实操分析。我们的博客主要有:网站首页、文章分类列表页、搜索列表页、标签列表页、文章内容展示页、单页面(联系我们)。其中,文章分类列表页、搜索列表页、标签列表页这三个页面展示结构都一样我们只需要......
  • Django 模板table 自增序号列
    第一种方法:<styletype="text/css">table{counter-reset:tableCount;}.counterCell:before{content:counter(tableCount);counter-increment:tableCount;}</style>标签中使用<table><tr><......
  • django模板使用的总结
    一、静态资源的引入方式1.在项目根目录下创建static文件夹。2.settings.py中配置环境变量,方便程序可以识别此路径。要在STATIC_URL='/static/'下边添加下面代码STATICFILES_DIRS=[os.path.join(BASE_DIR,'static'),]或STATICFILES_DIRS=os.path.join(BAS......
  • Python基础day61 Django choices参数和Ajax技术简介
    choices参数的使用choices是ORM中常用字段的参数作用:类似于一些字段:性别、学历、客户来源、是否上学、是否结婚等有限较少选择的字段我们在表中存储的时候一般使用choices参数,用数字替代文字。案例classCustomer(models.Model):"""客户表"""qq=m......
  • Django博客开发教程:创建项目
    我们对需求和数据库都进行分析了之后,我们就开始来创建我们的项目。教程是在windows10操作系统下,用的Python3.6和django2.1.1,开发工具为pycharm。打开我们的Pycharm,新建一个项目。说明:1为项目保存路径,myblog为项目名。2为选择使用的虚拟环境软件,这里选virtualenv。3为虚拟环境......
  • 1、Django博客开发教程:开发前的准备
    开发前的准备:1、安装好Python环境。Python3安装详细步骤2、安装好virtualenv虚拟环境。virtualenv虚拟环境安装方法3、安装好Pycharm开发工具。 ......
  • Django-4.2博客开发教程:数据库操作-页面动态展示数据库中的数据(十)
    1、数据准备工作首先增加2篇文章用于展示数据。 我用的mysql数据库,使用pycharm的DBBrowser进行数据查询。双击blog库下面对应的文章表,则显示当前数据。 2、查询数据并动态展示models.py里的类就是一个模板,在views.py引入并实例化。即将值查询出来并赋值到一个对象,在页......
  • python esp32 json pyserial
    esp32:#include<ArduinoJson.h>voidsetup(){Serial.begin(9600);}voidloop(){if(Serial.available()){//读取串口输入的数据StringjsonString=Serial.readStringUntil('\n');//创建JSON文档StaticJsonDocument<300>......