在Go语言中复制循环变量的地址。

huangapple go评论79阅读模式
英文:

Copying the address of a loop variable in Go

问题

在下面的代码示例中,结果不符合我的预期:

package main

import "fmt"

func main() {
    src := map[int]int{1: 1, 2: 2, 3: 3}
    fmt.Println("src ", src)
    
    dst := make([]*int, 0, len(src))
    for k, _ := range src {
        dst = append(dst, &k)
    }
    for _, a := range dst {
        fmt.Print(*a, " ")
    }
    fmt.Println()
}

结果:

src map[1:1 2:2 3:3]
3 3 3

Go Playground: https://play.golang.org/p/BSDsd3nojz

但是我理解发生了什么。k 的地址没有改变,它被添加到 dst 中,所以当我遍历 dst 时,每个位置都有相同的值:3

在循环中,k 的地址从未改变,所以第二个循环继续引用该位置,其中包含它最后拥有的值 3

我如何才能复制当前值 k 的地址?我是否需要像这样做:

for k, _ := range src {
    key := new(int)
    *key = k
    dst = append(dst, key)
}

这看起来很笨拙。

英文:

In the following code sample, the result is not what I would expect:

package main

import "fmt"

func main() {
	src := map[int]int{1: 1, 2: 2, 3: 3}
	fmt.Println("src ", src)
	
	dst := make([]*int, 0, len(src))
	for k, _ := range src {
		dst = append(dst, &k)
	}
	for _, a := range dst {
		fmt.Print(*a, " ")
	}
	fmt.Println()
}

Result:

src map[1:1 2:2 3:3]
3 3 3

Go Playground: https://play.golang.org/p/BSDsd3nojz

but I understand what is happening. The unchanging address of k is being added to dst, so when I loop over dst, the same value is in every location: 3.

The address of k never changes in the loop, so the second loop keeps referring to that location, containing the last value it had, 3.

How can I get the address of the current value of k to be copied? Do I need something like this:

for k, _ := range src {
    key = new(int)
    *key = k
    dst = append(dst, key)
}

That seems awkward.

答案1

得分: 8

如果你有一个map[T]X并且想要得到一个[]*T,你可以通过复制循环变量并获取其地址来实现。

有一种比你的方法更简洁的方式:

for k := range src {
    key := k
    dst = append(dst, &key)
}

你添加到dst的不是map中键或值的地址,而是键的副本的地址。这个区别可能对你有所影响,也可能没有。

使用循环变量的地址不起作用的原因是,循环变量是单个位置,在每次迭代时会更新。像int和struct这样的值类型在赋值给新变量时会被复制。

英文:

If you have a map[T]X and you want to get a []*T, you are on the right track with copying the loop variable and getting an address to it.

There is a slightly slimmer way to do it than your way:

for k := range src {
    key := k
    dst = append(dst, &key)
}

What you are adding to dst is not the address of the keys or values in the map, but rather the address of a copy of the key. That distinction may or may not matter to you.

The reason that using the address of the loop variables doesn't work, is that the loop variables are single locations that get updated on each iteration. Value types like ints and structs are copyed each time you assign it to a new variable.

答案2

得分: 0

我建议使用数组索引进行迭代,而不是值。这样你可以引用原始对象,而不是复制它们:

    for i, _ := range src {
        dst = append(dst, &src[i])
    }
英文:

I would suggest using the array indices for iteration, rather than values. This way you can reference the original objects instead of copying them around:

    for i, _ := range src {
        dst = append(dst, &src[i])
    }

huangapple
  • 本文由 发表于 2017年8月31日 02:20:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/45967305.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定