golang for,range的坑

for,range 的k,v变量在整个遍历过程中共用,不能直接进行引用传递,即地址传递,但循环内定义的变量只能为当前循环所使用。

错误代码:

package main

import (
    "encoding/json"
    "log"
    "time"
)

type test struct {
    Name string `bson:"name" json:"name" yaml:"name"` // Command name (unique on the profile)
}

func (test test) String() string {
    out, err := json.Marshal(test)
    if err != nil {
        return err.Error()
    }
    return string(out)
}

func main() {
    var a, b, c test
    a.Name = "a"
    b.Name = "b"
    c.Name = "c"
    src := []test{a, b, c}
    log.Println(src)
    var dec []*test
    for _, v := range src {
        log.Println(v)
        dec = append(dec, &v)
    }
    time.Sleep(1 * time.Second)
    log.Println(dec)
}

输出结果:


2019/03/20 13:28:34 [{"name":"a"} {"name":"b"} {"name":"c"}]
2019/03/20 13:28:34 {"name":"a"}
2019/03/20 13:28:34 {"name":"b"}
2019/03/20 13:28:34 {"name":"c"}
2019/03/20 13:28:35 [{"name":"c"} {"name":"c"} {"name":"c"}]

示例代码对test结构体定义了String方法,会打印地址指向的具体内容,详情见我另外一篇文章:利用fmt.Stringer 接口实现自定义日志打印

示例代码输出dec结果所有成员皆为遍历的最后一个地址,非预期值,正确使用应如下:

package main

import (
    "encoding/json"
    "log"
    "time"
)

type test struct {
    Name string `bson:"name" json:"name" yaml:"name"` // Command name (unique on the profile)
}

func (test test) String() string {
    out, err := json.Marshal(test)
    if err != nil {
        return err.Error()
    }
    return string(out)
}

func main() {
    var a, b, c test
    a.Name = "a"
    b.Name = "b"
    c.Name = "c"
    src := []test{a, b, c}
    log.Println(src)
    var dec []*test
    for _, v := range src {
        value := v
        dec = append(dec, &value)
    }
    time.Sleep(1 * time.Second)
    log.Println(dec)
}

输出结果:

2019/03/20 13:36:41 [{"name":"a"} {"name":"b"} {"name":"c"}]
2019/03/20 13:36:42 [{"name":"a"} {"name":"b"} {"name":"c"}]

你可能感兴趣的:(golang for,range的坑)