go结构体中的匿名变量在json.marshal中隐藏的坑
- 2020 年 3 月 26 日
- 笔记
故障背景
在昨天的工作中,遇到一个诡异的小问题,调试了一段时间,在网上也没有找到相关材料(可能谷歌能力有限,搜索不到,要用百度)。先来看一段简单的简化后的代码,简单、清晰、明了、接地气,与我的工作场景一致。
/* * Copyright (c) 2020. * [email protected] */ package main import ( "encoding/json" "fmt" ) type L5 struct { Modid int64 `json:"modid"` Cmdid int64 `json:"cmdid"` } type CommonAttr struct { Name string `json:"name"` Desc string `json:"desc"` } type OperationQueryCKV struct { L5 Expression string `json:"expression"` TimeoutMs int64 `json:"timeout_ms"` } type Operation struct { CommonAttr *OperationQueryCKV } func main() { op := &Operation{ CommonAttr{ Name: "op_name", Desc: "op_desc", }, &OperationQueryCKV{ L5: L5{ Modid: 12345, Cmdid: 54321, }, Expression: "expression", TimeoutMs: 80, }, } b, _ := json.MarshalIndent(op,"","t") fmt.Printf("%sn", string(b)) }
关注一下L5结构,这是一种公司内部服务负载均衡和服务发现的公共件,简单的说,一个L5可以换到一个IP和端口列表,然后拿去访问服务。对于CKV查询功能来说,需要一个L5表明CKV在哪。
漫天飞舞的匿名字段,是不是像golang大神特有的标签。运行一下,没问题,符合预期,完美。
[root@VM_15_146_centos ~]# go run main.go { "name": "op_name", "desc": "op_desc", "modid": 12345, "cmdid": 54321, "expression": "expression", "timeout_ms": 80 }
故障现象
有一天,这样跑了一年的代码突然就不对了,测试发现,OperationQueryCKV结构序列化之后modid和cmdid都消失了,很邪乎。告诉我这个问题后,我也是一脸懵,我最近没有改动相关代码呀。都跑了一年了你跟我说这东西不行了?
故障原因
查看代码提交记录,一处改动进入视野,最近新增了一个查询数据库的功能,与OperationQueryCKV类似的,新增定义了一个OperationQuerySQL,只是新定义了结构,还没有实现和严格测试。
type OperationQuerySQL struct { L5 User string `json:"user"` Pwd string `json:"pwd"` } type Operation struct { CommonAttr *OperationQueryCKV *OperationQuerySQL }
查询数据库也需要一个L5,一贯风格,新增一个L5的匿名变量,完活。估计就是两个匿名L5,把值搞没了。试着跑一下样例代码。
func main() { op := &Operation{ CommonAttr{ Name: "op_name", Desc: "op_desc", }, &OperationQueryCKV{ L5: L5{ Modid: 12345, Cmdid: 54321, }, Expression: "expression", TimeoutMs: 80, }, nil, } b, _ := json.MarshalIndent(op, "", "t") fmt.Printf("%sn", string(b)) }
结果,我的L5果然没有了。根本原因应该是匿名变量导致的json字段key重复。
{ "name": "op_name", "desc": "op_desc", "expression": "expression", "timeout_ms": 80 }
解决方法
这样的坑,在分工合作时会不经意引入,有时比较隐晦。
暂时也不知道好的办法,建议是不用或者少用匿名字段,如果需要使用匿名字段,每项都定义不同的`json:"_key_“`。