
昨天写代码的时候因为变量作用域的问题被坑了好久,在这里记录一下,避免今后再犯。
先看下面这段代码,大致功能是为传进来的引用填充一个带有自增的 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 { |