golang json.Unmarshal()不清除结构体原有变量的值

背景
在某项目中,由于技术升级或者提升产品适用场景,需要对寻址参数进行修改,公司内寻址用的modid和cmdid两个整数统一使用字符串addr替代,便于兼容ipvs等。
为减少兼容代码,存储在zookeeper中的存量配置数据需要做结构转换,这活我干了。

故障代码

多么简单单纯的代码,每天都这样搬砖,职业生涯是道不了35岁的,也许30岁就可以退休了。

func (act *AccessCfgsTool) convert() {
	// 读出Task信息后,清理掉L5的两个整数后写回
        var task mc_proto.Task
	for _, v := range act.taskIDs {		
		//处理access_cfg配置
		path := fmt.Sprintf("%s/%d", TASK_PATH, v)
		fmt.Printf("converting %s.\n", path)
		_, err := zkutil.ZkReadJson(act.conn.conn, path, &task)		
		//做转换处理 XXXXXXXX
		err = zkutil.ZkUpdateJson(act.conn.conn, path, -1, &task)		
		fmt.Printf("convert %s done.\n", path)
	}
}

故障现象

在测试环境上线后,过了几天,一位大哥跟我说,数据怎么是乱的,为什么这个任务的配置上,会有其他任务的信息?

我蒙蔽了,但是无知让我无畏:怎么可能,一定是你们做了什么操作,搞乱了。
外强中干的我赶紧看看转换代码,发现了可能的原因,并简单的测试了一下。

func TestUnMarshal() {
   type T struct {
      A string
      B string
   }
   t := T{A: "hello,world,A"}
   str := "{\"B\":\"hello,world,B\"}"
   json.Unmarshal([]byte(str), &t)
   fmt.Printf("%v\n", t)
}

D:\xxx\src\paper>go run main.go
{hello,world,A hello,world,B}

故障原因

到这里大概都知道故障的原因了,对转换代码做下修正。

func (act *AccessCfgsTool) convert() {
	// 读出Task信息后,清理掉L5的两个整数后写回
        //移动到下面第二行 var task mc_proto.Task
	for _, v := range act.taskIDs {		
                var task mc_proto.Task
		//处理access_cfg配置
		path := fmt.Sprintf("%s/%d", TASK_PATH, v)
		fmt.Printf("converting %s.\n", path)
		_, err := zkutil.ZkReadJson(act.conn.conn, path, &task)		
		//做转换处理 XXXXXXXX
		err = zkutil.ZkUpdateJson(act.conn.conn, path, -1, &task)		
		fmt.Printf("convert %s done.\n", path)
	}
}

问题解决了。

结论

golang json.Unmarshal()不会替我们清除已有变量的值,只会用解析出的值进行覆盖赋值。