• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

golang反序列化json,不存在的字段设置默认值

武飞扬头像
HNU_GeorgeYang
帮助2

问题

业务里要调第三方接口,返回的json里有俩字段可能有,也可能没有。

没有的情况和为0值的情况对应不同的业务逻辑,在编写代码的时候发现没法在struct上指定字段默认值。

其实可以先给struct的实例设置默认值,再去json.Unmarshal,但是第三方接口返回的json是一个嵌套的数组结构,我压根不知道json里面的BehaviorData数组有多少元素,没法这么玩。

解决方案

  1. 给对应的struct重写UnmarshalJSON方法
type BehaviorData struct {
	AverageReplyTime      int     `json:"avg_reply_time"`
	ReplyPercentage       float32 `json:"reply_percentage"`
}

func (b *BehaviorData) UnmarshalJSON(data []byte) error {
	// 给目标struct取个别名  避免下面Unmarshal(data, defaultData)时循环调用本方法
	type BehaviorDataAlia BehaviorData
	// 在序列化之前就设置好默认值
	defaultData := &BehaviorDataAlia{
		AverageReplyTime: -1,
		ReplyPercentage:  -1,
	}

	// json串反序列化到这个defaultData里  如果有字段缺席 那么刚刚写的默认值就会留下
	_ = json.Unmarshal(data, defaultData)
	// 本质上就是在b这个实例调用自身的Unmarshal前后包装了一下  这里把包装之后的data覆盖到b上去
	*b = BehaviorData(*defaultData)
	return nil
}
学新通

类似问题

struct在marshal成json字符串的时候,希望有自定义值/默认值

  1. 利用反射,自己封装unmarshal方法,利用反射来读取struct字段中的tag
    type test struct {
        Name     string `json:"name"`
        Addr     string `json:"addr" default:"localhost"`
        Port     uint   `json:"port" default:"8080"`
    }
    
    func MarshalJson(i interface{}) ([]byte, error) {
        typeof := reflect.TypeOf(i)
        valueof := reflect.ValueOf(i)
        // 遍历这个obj的所有字段
        for i := 0; i < typeof.Elem().NumField(); i   {
        	// 针对那些为0值得
            if valueof.Elem().Field(i).IsZero() {
                def := typeof.Elem().Field(i).Tag.Get("default")
                if def != "" {
                    switch typeof.Elem().Field(i).Type.String() {
                    case "int":
                        result, _ := strconv.Atoi(def)
                        valueof.Elem().Field(i).SetInt(int64(result))
                    case "uint":
                        result, _ := strconv.ParseUint(def, 10, 64)
                        valueof.Elem().Field(i).SetUint(result)
                    case "string":
                        valueof.Elem().Field(i).SetString(def)
                    }
                }
            }
        }
        return json.Marshal(i)
    }
    
    func main() {
        t := &test{
            Name:     "test server",
        }
    
        data, err := MarshalJon(t)
        if err != nil {
            panic(err)
        }
        fmt.Println(string(data))
    }
    
    结果:
    {"name":"test server","addr":"localhost","port":8080}
    
    学新通
  2. 重写该struct的MarshalJSON方法,利用匿名结构体重复字段覆盖的机制
    func (d Message) MarshalJSON() ([]byte, error) {
    	type Alias Message
    	return json.Marshal(struct {
    		Alias
    		CreateAt string `json:"createAt"`
    	}{
    		Alias:      Alias(d),
    		CreateAt: d.CreateAt.Format("2006/01/02 15:04:05"),
    	})
    }
    
    还可以通过类似方法给序列化之后的json串添加额外的字段
    type Book struct {
      Title        string
      Author       string
    }
    
    type FakeBook Book
     
    func (b Book) MarshalJSON() ([]byte,error) {
        return json.Marshal(struct {
            FakeBook
            Genre string
        }{
            FakeBook: FakeBook(b),Genre:    "Satire",})
    }
    
    //对Book对象的序列化结果:
    {
      "Title": "Catch-22","Author": "Joseph Heller","Genre": "Satire"	//可以发现确实多了一个Genre字段
    }
    
    
    学新通
    详见文章golang重载MarshalJSON实现自定义序列化

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhhbakaj
系列文章
更多 icon
同类精品
更多 icon
继续加载