Golang中的坑二

for ...range

最近两周用Golang做项目,编写web服务,两周时间写了大概五千行代码(业务代码加单元测试用例代码)。用Go的感觉很爽,编码效率高,运行效率也不错,用了beego,avro,xorm,反射。今天和前端联调遇到了一个bug,发现踩到了第二个坑。踩坑不怕,踩过一次就不会再犯了,这就是实践的好处。

坑是这样的:数据采用avro描述,用xorm存取到mysql;对于有嵌套的数据结构,avro生成的go结构体以指针切片的形式声明,xorm Find方法采用了结构体切片的形式。有如下avro schema:

{

"fields": [

{

"name": "Oid",

"type": "int"

},

{

"name": "name",

"type": "string"

},

{

"name": "inner_objs",

"type": {

"items": {

"fields": [

{

"name": "Iid",

"type": "int"

},

{

"name": "name",

"type": "string"

},

{

"name": "degree",

"type": "int"

}

],

"name": "inner_obj",

"type": "record"

},

"type": "array"

}

}

],

"name": "outer_obj",

"type": "record"

}

对应的go结构体及数据操作函数如下:

package models

type OuterObj struct {

Oid int32 `json:"oid" xorm:"pk notnull"`

Name string `json:"name"`

InnerObjs []*InnerObj `json:"inner_objs"`

}

type InnerObj struct {

Oid int32 `json:"-" xorm:"pk notnull"`

Iid int32 `json:"iid" xorm:"pk notnull"`

Name string `json:"name"`

Degree int32 `json:"degree"`

}

func GetOuterObjs(index int, count int) (objs []OuterObj, err error) {

objs = make([]OuterObj, 0)

err = x_intellitbi.Asc("oid").Limit(count, (index-1)*count).Find(&objs)

if err != nil {

return

}

for index := 0; index < len(objs); index++ {

objs[index].InnerObjs = make([]*InnerObj, 0)

innerObjs := make([]InnerObj, 0)

err = x_intellitbi.Where("oid=?", objs[index].Oid).Find(&innerObjs)

if err != nil {

return

}

for _, v := range innerObjs {

objs[index].InnerObjs = append(objs[index].InnerObjs, &v)

}

}

Return

}

GetOuterObjs返回的结果不符合预期,每个OuterObj实例内的InnerObjs对应的内容全部相同。

潜意识里,肯定有一部分人对带有短变量声明(short variable declaration :=)的for...range的理解是:每次迭代声明一个不同的变量。用Google搜了下,在2011年golang-nuts上确实有过关于该问题的讨论(https://groups.google.com/forum/#!topic/golang-nuts/e08r1Vk7ufQ)。

继续查看golang spec  For statements with range clause 部分

最新的spec中有说明:

The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration. If the iteration variables are declared outside the "for" statement, after execution their values will be those of the last iteration.

翻译如下:

迭代变量可以由“range”子句使用一个短变量声明(:=)形式声明。在这种情况下,它们的类型设置为相应迭代值的类型,其范围是“for”语句的块;它们在每次迭代中被重用。如果迭代变量在“for”语句之外被声明,执行后它们的值将是上一次迭代的值。

用:=声明的迭代变量在每次迭代过程中被重用了,应该可以理解成在for作用域内声明了迭代变量,在for内可见,每次迭代过程中被重新评估值;与在for外部声明迭代变量类似,区别是作用域不同。

另外再说下xorm,InsertMulti采用了指针切片,Find采用了结构体切片的指针,如果Find统一成指针切片就更好了,这样也免得多一层转换。

Golang中的坑二的更多相关文章

  1. Golang 中的坑 一

    Golang 中的坑 短变量声明  Short variable declarations 考虑如下代码: package main import ( "errors" " ...

  2. golang中生成读取二维码(skip2/go-qrcode和boombuler/barcode,tuotoo/qrcode)

     1 引言 在github上有好用golan二维码生成和读取库,两个生成二维码的qrcode库和一个读取qrcode库. skip2/go-qrcode生成二维码,github地址:https://g ...

  3. Golang中WaitGroup使用的一点坑

    Golang中WaitGroup使用的一点坑 Golang 中的 WaitGroup 一直是同步 goroutine 的推荐实践.自己用了两年多也没遇到过什么问题.直到一天午睡后,同事扔过来一段奇怪的 ...

  4. Golang的防坑小技巧

    Golang的防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名小白,在之前没有接触到编程的小伙伴,难免会踩到一些坑,比如说刚刚入门的时候你需要安装环境,学习Gol ...

  5. 【荐】详解 golang 中的 interface 和 nil

    golang 的 nil 在概念上和其它语言的 null.None.nil.NULL一样,都指代零值或空值.nil 是预先说明的标识符,也即通常意义上的关键字.在 golang 中,nil 只能赋值给 ...

  6. Golang 中使用多维 map

    http://tnt.wicast.tk/2015/11/02/golang-multiple-dimension-map/ Golang 的 XML/JSON 解析库乍看使用起来很方便,只要构造一样 ...

  7. golang中,slice的几个易混淆点

    slice在golang中是最常用的类型,一般可以把它作为数组使用,但是比数组要高效呀.不过,我感觉这个东西用的不好坑太多了.还是需要了解下他底层的实现 slice的结构定义 type slice s ...

  8. 初学者学习golang可能遇到的坑

    我也是个golang初学者,刚入门的话,有些"坑"还是不好发现的.如map只是定义了然后就拿来使用,变量的值覆盖等. 本来打算写一篇的,后面发现有人写的挺不错的,我就把里面的有些坑 ...

  9. 菜鸟帮你跳过openstack配置过程中的坑

    一:前言 对于一个以前做java全栈工程师而言,而且没学过Linux,很少用虚拟机(还是在大学的时候简单的用过),去配置openstack我想我入的坑肯定比有基础的一定要多,躺在每个坑中徘徊思索的时间 ...

随机推荐

  1. 2016普及组t3海港

    好的,说说这道题的思路,爆搜队列嘛: 用一个结构体队列存每个人来的时间和他的国籍,用一个vis数组存每个人来的次数,是第一次来sum便加一. 然后从前面第一个人开始扔(原谅我用这个词,因为我找不到更好 ...

  2. Spring Cloud 之 Feign

    新建Spring Boot工程,命名为feign 1.pom.xml添加依赖 <?xml version="1.0" encoding="UTF-8"?& ...

  3. zzuli 1817: match number 模拟

    1817: match number Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 199  Solved: 72 SubmitStatusWeb B ...

  4. PHP获取一周的日期

    /** * 获取一周日期 * @param $time 时间戳 * @param $format 转换格式 */ function get_week($time, $format = "Y- ...

  5. Hibernate框架进阶(中篇)之多表关系

    导读 Hibernate进阶主要分为上中下三篇,本文是中篇,主要讲解Hibernate框架中多表关系的实现.我们知道多表关系有一对一.一对多(多对一)和多对多三种关系.而1对1关系一般合并为一个表处理 ...

  6. [译]在Asp.Net Core 中使用外部登陆(google、微博...)

    原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET Core> 摘要:本文主要介绍了使用外部登陆提供程序登陆的流程,以及身份 ...

  7. 再说Postgres中的高速缓存(cache)

    表的模式信息存放在系统表中,因此要访问表,就需要首先在系统表中取得表的模式信息.对于一个PostgreSQL系统来说,对于系统表和普通表模式的访问是非常频繁的.为了提高这些访问的效率,PostgreS ...

  8. inotify软件部署及实时同步

    声明:博主使用的是CentOS6.9的系统 参考资料: https://github.com/rvoicilas/inotify-tools/wiki http://www.ibm.com/devel ...

  9. Python爬虫(十三)_案例:使用XPath的爬虫

    本篇是使用XPath的案例,更多内容请参考:Python学习指南 案例:使用XPath的爬虫 现在我们用XPath来做一个简单的爬虫,我们尝试爬取某个贴吧里的所有帖子且将该帖子里每个楼层发布的图片下载 ...

  10. 用HTML5实现的各种排序算法的动画比較

    用HTML5实现的各种排序算法的动画比較 非常有意思,详见: http://www.webhek.com/misc/comparison-sort/