zoukankan      html  css  js  c++  java
  • Golang中的坑二

    Golang中的坑二

    for ...range

    最近两周用Golang做项目,编写web服务,两周时间写了大概五千行代码(业务代码加单元测试用例代码)。用Go的感觉很爽,编码效率高,运行效率也不错,用了beegoavro,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搜了下,在2011golang-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外部声明迭代变量类似,区别是作用域不同。

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

  • 相关阅读:
    131. 分割回文串
    博客开通第二十七天
    博客开通第三十八天
    博客开通第56天
    博客开通第三十三天
    博客开通第61天
    博客开通第62天
    博客开通第二十六天
    博客开通第四十七天
    博客开通第63天
  • 原文地址:https://www.cnblogs.com/majianguo/p/6781819.html
Copyright © 2011-2022 走看看