最近测试反馈了一个奇怪的bug:
“编辑当前行的时候,在提交保存 之后。未填写数据的部分,自动使用了上一行 的值”
排查 接到这个问题的时候,我最开始怀疑是不是前端把数据报错了。于是打开F12,看了一下网络请求。 在进行多次复现尝试后,确认不是前端的问题。于是开始复核后端代码。 在处理数据部分,将代码抽象成以下逻辑,便于表达。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "encoding/json" "fmt" ) type User struct { Card string Name string Age int } func main () { jsonUserOne = []byte (`[{"Card":"A001","Name":"张三","Age":10}]` ) jsonUserTwo = []byte (`[{"Name":"李四"}]` ) var userSlice []User _ = json.Unmarshal(jsonUserOne, &userSlice) fmt.Println("------------user one------------" ) userOne, _ = json.Marshal(userSlice) fmt.Println(string (userOne)) _ = json.Unmarshal(jsonUserTwo, &userSlice) fmt.Println("------------user two------------" ) userTwo, _ = json.Marshal(userSlice) fmt.Println(string (userTwo)) }
定位问题 第一眼看上去,上面的代码好像没什么问题。可是添加log打印后,发现了问题
打印结果 1 2 3 4 ------------user one------------ [{"Card":"A001","Name":"张三","Age":10}] ------------user two------------ [{"Card":"A001","Name":"李四","Age":10}]
嗯?为什么属性没有清空。和期望的 [{"Card":"","Name":"李四","Age":0}]
不一样
那如果我们加上清空Slice尝试呢
尝试清空 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package mainimport ( "encoding/json" "fmt" ) type User struct { Card string Name string Age int } func main () { jsonUserOne = []byte (`[{"Card":"A001","Name":"张三","Age":10}]` ) jsonUserTwo = []byte (`[{"Name":"李四"}]` ) var userSlice []User _ = json.Unmarshal(jsonUserOne, &userSlice) fmt.Println("------------user one------------" ) userOne, _ = json.Marshal(userSlice) fmt.Println(string (userOne)) userSlice = userSlice[:0 ] _ = json.Unmarshal(jsonUserTwo, &userSlice) fmt.Println("------------user two------------" ) userTwo, _ = json.Marshal(userSlice) fmt.Println(string (userTwo)) }
更改后的代码,添加了 userSlice = userSlice[:0]
清空slice的操作。 执行后日志如下:
1 2 3 4 ------------user one------------ [{"Card":"A001","Name":"张三","Age":10}] ------------user two------------ [{"Card":"A001","Name":"李四","Age":10}]
嗯?怎么还不对
换一种清空方式 将
1 userSlice = userSlice[:0 ]
更改为
执行后日志如下:
1 2 3 4 ------------user one------------ [{"Card":"A001","Name":"张三","Age":10}] ------------user two------------ [{"Card":"","Name":"李四","Age":0}]
世界终于清净了
问题拓展 那么,Slice有这样的问题,直接Struct呢,会不会也出现这样的问题呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package mainimport ( "encoding/json" "fmt" ) type User struct { Card string Name string Age int } func main () { jsonUserOne := []byte (`{"Card":"A001","Name":"张三","Age":10}` ) jsonUserTwo := []byte (`{"Name":"李四"}` ) var user User _ = json.Unmarshal(jsonUserOne, &user) fmt.Println("------------user one------------" ) userOne, _ := json.Marshal(user) fmt.Println(string (userOne)) _ = json.Unmarshal(jsonUserTwo, &user) fmt.Println("------------user two------------" ) userTwo, _ := json.Marshal(user) fmt.Println(string (userTwo)) }
执行后日志如下:
1 2 3 4 ------------user one------------ {"Card":"A001","Name":"张三","Age":10} ------------user two------------ {"Card":"A001","Name":"李四","Age":10}
涛声依旧
将 // user = User{}
注释解除 执行后日志如下:
1 2 3 4 ------------user one------------ {"Card":"A001","Name":"张三","Age":10} ------------user two------------ {"Card":"","Name":"李四","Age":0}
问题总结 这里不是从GolangSDK源码级别的解释。仅从我们这次发现的bug进行总结。
json.Unmarshal
的运行规则,是从字符串中取出值,设置到对应的结构体的同Key上。在此之前,并不会清空该结构体已有的数据
在Slice执行userSlice = userSlice[:0]
这样的操作,并不能释放 该Slice所占用的空间(可以使用cap(userSlice)
查看)。保守的做法userSlice = nil
在使用 json.Unmarshal
之前,应重新初始化对应的结构体(Slice、Struct)