Golang中的坑二
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中的坑二的更多相关文章
- Golang 中的坑 一
Golang 中的坑 短变量声明 Short variable declarations 考虑如下代码: package main import ( "errors" " ...
- golang中生成读取二维码(skip2/go-qrcode和boombuler/barcode,tuotoo/qrcode)
1 引言 在github上有好用golan二维码生成和读取库,两个生成二维码的qrcode库和一个读取qrcode库. skip2/go-qrcode生成二维码,github地址:https://g ...
- Golang中WaitGroup使用的一点坑
Golang中WaitGroup使用的一点坑 Golang 中的 WaitGroup 一直是同步 goroutine 的推荐实践.自己用了两年多也没遇到过什么问题.直到一天午睡后,同事扔过来一段奇怪的 ...
- Golang的防坑小技巧
Golang的防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名小白,在之前没有接触到编程的小伙伴,难免会踩到一些坑,比如说刚刚入门的时候你需要安装环境,学习Gol ...
- 【荐】详解 golang 中的 interface 和 nil
golang 的 nil 在概念上和其它语言的 null.None.nil.NULL一样,都指代零值或空值.nil 是预先说明的标识符,也即通常意义上的关键字.在 golang 中,nil 只能赋值给 ...
- Golang 中使用多维 map
http://tnt.wicast.tk/2015/11/02/golang-multiple-dimension-map/ Golang 的 XML/JSON 解析库乍看使用起来很方便,只要构造一样 ...
- golang中,slice的几个易混淆点
slice在golang中是最常用的类型,一般可以把它作为数组使用,但是比数组要高效呀.不过,我感觉这个东西用的不好坑太多了.还是需要了解下他底层的实现 slice的结构定义 type slice s ...
- 初学者学习golang可能遇到的坑
我也是个golang初学者,刚入门的话,有些"坑"还是不好发现的.如map只是定义了然后就拿来使用,变量的值覆盖等. 本来打算写一篇的,后面发现有人写的挺不错的,我就把里面的有些坑 ...
- 菜鸟帮你跳过openstack配置过程中的坑
一:前言 对于一个以前做java全栈工程师而言,而且没学过Linux,很少用虚拟机(还是在大学的时候简单的用过),去配置openstack我想我入的坑肯定比有基础的一定要多,躺在每个坑中徘徊思索的时间 ...
随机推荐
- Android Weekly Notes Issue #286
December 3rd, 2017 Android Weekly Issue #286 本期文章包含如何通过踩坑来学习Kotlin,以及利用Kotlin的data class做MVVM状态保存,还包 ...
- Retrofit网络请求库应用01
PS:什么是Retrofit? 在官方文档中有这样一句话--A type-safe HTTP client for Android and Java(一个类型安全的http client库),具体的话 ...
- appium测试准备记录
一 获取应用程序包名(手机中不安装apk) windows 环境下: aapt工具 使用aapt工具,适合给程序自动获取apk的相关信息. //aapt 是sdk自带的一个工具,在SDK/buildt ...
- 优先队列 poj3253 Fence Repair
Fence Repair Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 51411 Accepted: 16879 De ...
- backbone与require的共存问题解决
如果向下面那样直接列出script标签可能会出现错误, <script type="text/javascript" src="/dep/jquery-1.11 ...
- 》》QQ-注册
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Scala环境搭建之eclipse
由于Spark的缘故.我们来看看另外一门语言--Scala,为什么要看这门语言呢?唉~事实上你不看也没关系,仅仅只是spark的内核就是用Scala写的.spark也提供其它语言的编程模型....看自 ...
- 《Pro Android Graphics》读书笔记之第六节
Android UI Layouts: Graphics Design Using the ViewGroup Class Android ViewGroup Superclass: A Founda ...
- Order笔记-数据库创建
过程: 1,为这个项目新建一个用户名(实例),专门用于这个项目 2,建表 问题: 列在此处不允许: 笔记: 建表设置默认值: alter table 表名 modify 字段名 default 默认值 ...
- 小白的Python之路 day2 列表、元组操作
1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 1 names = ['Tom','Jack','Qian'] 通过下标访问列表中 ...