昨天写代码的时候因为变量作用域的问题被坑了好久,在这里记录一下,避免今后再犯。
先看下面这段代码,大致功能是为传进来的引用填充一个带有自增的 ID
的对象,同时这个 ID
中不能包含 4,自增 ID
是使用 Redis 的 incr
来维护的。
1 | func fillNewUserLiveRightAttribute(ctx context.Context, userLiveRight *po.UserLiveRight, right *po.LiveRight) error { |
但是之后发现填充进去的 ID
永远是 0,检查了一下 Redis 中 那个自增 ID 也确实存在。
这里当时还饶了一下远路,因为那个 Attribute
字段在数据库中使用 jsonb 存储的,所以我前期先检查了插入时执行的 SQL
语句,发现每次 Attribute
都是打印的 {}
,就以为是我自己没有赋上值。真实的原因是我指定了 Attribute
中的 ID
字段在转 Json 时启用 omitempty
,即:
1 | type UserLiveRightAttribute struct { |
使用 omitempty
可以告诉 Marshal
函数如果 field
的值是对应类型的 zero-value
,那么序列化之后的 JSON object 中不包含此 字段,所以 ID=0
转 Json 后自然就没有这个字段了。
回到为啥上边的代码拿到的 ID
总是 0 的问题:因为 for
中赋值的 incrId
是在一个新的作用域内,只在 for 的花括号内有效,退出 for 后拿到的是最开始初始化 incrId
的 0 值,这里使用的 := 进行的赋值,因为 err 是个新字段,所以并没有提示错误。
修复方法很简单,err 也在作用域外声明,里边使用 =
来赋值。
1 | func fillNewUserLiveRightAttribute(ctx context.Context, userLiveRight *po.UserLiveRight, right *po.LiveRight) error { |