Golang中的坑二

Golang中的坑二

for ...range前端

 

最近兩週用Golang作項目,編寫web服務,兩週時間寫了大概五千行代碼(業務代碼加單元測試用例代碼)。用Go的感受很爽,編碼效率高,運行效率也不錯,用了beegoavro,xorm,反射。今天和前端聯調遇到了一個bug,發現踩到了第二個坑。踩坑不怕,踩過一次就不會再犯了,這就是實踐的好處。mysql

坑是這樣的:數據採用avro描述,用xorm存取到mysql;對於有嵌套的數據結構,avro生成的go結構體以指針切片的形式聲明,xorm Find方法採用告終構體切片的形式。有以下avro schemagolang

 

{web

"fields": [sql

{json

"name": "Oid",數據結構

"type": "int"app

},ide

{函數

"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統一成指針切片就更好了,這樣也省得多一層轉換。

相關文章
相關標籤/搜索