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我想我入的坑肯定比有基础的一定要多,躺在每个坑中徘徊思索的时间 ...
随机推荐
- 熟悉Objective—C
1.oc使用消息结构而非函数调用 使用消息结构的语言,运行时所应执行的代码由运行环境来决定,而是用函数调用的语言,则由编译器决定.函数调用:如果调用的函数是多态的,那么在运行时就要按照“虚方法表”来查 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(88)-Excel导入和导出-主从表结构导出
前言 前面一篇详细讲解了导入导出,本节演示混合结构的导出功能!同时提供代码下载.. 代码下载 vs2015+无数据库 先看效果图:这个一个混合的Excel,列表与自定义信息的混合! 我们的步骤大概分为 ...
- [设计模式]PHP设计模式之单例模式
面试最常见的问题之一就是 请问您知道哪些设计模式这次先介绍最经典的单例模式.单例模式分3种:懒汉式单例.饿汉式单例.登记式单例.单例模式有以下3个特点:1.只能有一个实例.2.必须自行创建这个实例. ...
- JavaScript学习笔记(十六)——面向对象编程
在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...
- CentOS7脱机安装SQL Server 2017
SQL Server on Linux也发布一段时间了,官方上支持Red Hat, SUSE, Ubuntu.手上没有以上Linux版本,选用了与Red Hat最接近的CentOS7.4来进行安装和测 ...
- Docker笔记四:Elasticsearch实例部署
在运行或启动elasticsearch容器前,先在宿主机上执行 sysctl -w vm.max_map_count=262144: 解决" max virtual memory areas ...
- Android开发中有用工具之--Log工具类
在开发的过程中.我们常常会使用Log来输出日志,帮助我们来调试程序 可是有时候并不能全然满足我们的须要 ,比方我想知道这个日志信息是来自于哪一个包 哪一个类 所以我们封装一个这个Log类.方便我们的使 ...
- HBase源代码分析之HRegion上MemStore的flsuh流程(一)
了解HBase架构的用户应该知道,HBase是一种基于LSM模型的分布式数据库.LSM的全称是Log-Structured Merge-Trees.即日志-结构化合并-树. 相比于Oracle普通索引 ...
- ado 字符串变量
这次变量主要针对 Mfc 的 Cstring 类型的变量(前面VC 链接Access 数据库 插入变量到表) 思路; 1 把cstring 类型 转为 string 2 string 转 char 数 ...
- OVS 总体架构、源码结构及数据流程全面解析
在前文「从 Bridge 到 OVS」中,我们已经对 OVS 进行了一番探索.本文决定从 OVS 的整体架构到各个组件都进行一个详细的介绍. OVS 架构 OVS 是产品级的虚拟交换机,大量应用在生产 ...