从另一个切片复制后,所有切片中的条目最终都变得相同。

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

All entries in slice end up identical after copying from another slice

问题

我有一个 uuid.UUID 元素的切片。根据源代码uuid.UUID 只是一个字节数组的类型别名:type UUID [16]byte

我试图使用以下代码将这个 uuid.UUID 切片转换为 []byte 切片:

package main

import (
	"fmt"
	"github.com/google/uuid"
)

func main() {
	ids := []uuid.UUID {
		uuid.New(),
		uuid.New(),
		uuid.New(),
	}
	fmt.Printf("ids: %v\n", ids)
	idBytes := make([][]byte, len(ids))
	for i, id := range ids {
		idBytes[i] = id[:]
	}
	fmt.Printf("idBytes: %x\n", idBytes)
}

playground 链接

由于某种原因,这会产生以下输出:

ids: [66b4bb26-3c1f-4dd7-a608-aa8f799e4bfe 014e0537-c326-4021-be38-165f49595eed 5c71efff-ddb5-4f6e-8f85-c1dab013b5d1]
idBytes: [5c71efffddb54f6e8f85c1dab013b5d1 5c71efffddb54f6e8f85c1dab013b5d1 5c71efffddb54f6e8f85c1dab013b5d1]

显然有 3 个不同的 UUID,但输出的切片只包含最后一个 UUID,重复了 3 次。这是怎么回事?

我尝试过的方法:

  1. 使用非切片类型而不是切片类型(即,使用 []uint64 作为输入和输出,而不是 []uuid.UUID 和 [][]byte)。这显示了预期的行为(我看到了 3 个不同的值,而不是最后一个值重复 3 次),但它并没有真正解决我的问题。
  2. 只设置最后一个元素(将 idBytes[i] = id[:] 放在一个 if i == len(ids) - 1 的块中)。这只设置了最后一个元素(前两个元素仍然为 nil)。
英文:

I have a slice of uuid.UUID elements. From the source, a uuid.UUID is just a type alias for a byte array: type UUID [16]byte.

I'm trying to convert this slice of uuid.Uuids to a slice of []byte using the following code:

package main

import (
	"fmt"
	"github.com/google/uuid"
)

func main() {
	ids := []uuid.UUID {
		uuid.New(),
		uuid.New(),
		uuid.New(),
	}
	fmt.Printf("ids: %v\n", ids)
	idBytes := make([][]byte, len(ids))
	for i, id := range ids {
		idBytes[i] = id[:]
	}
	fmt.Printf("idBytes: %x\n", idBytes)
}

playgroud link

For some reason, this produces the following output:

ids: [66b4bb26-3c1f-4dd7-a608-aa8f799e4bfe 014e0537-c326-4021-be38-165f49595eed 5c71efff-ddb5-4f6e-8f85-c1dab013b5d1]
idBytes: [5c71efffddb54f6e8f85c1dab013b5d1 5c71efffddb54f6e8f85c1dab013b5d1 5c71efffddb54f6e8f85c1dab013b5d1]

There are clearly 3 distinct UUIDs, but the output slice contains only the last one, repeated 3 times. What's going on here?

Things I've tried:

  1. Use a non-slice type instead of a slice type (that is, use []uint64 as input and output instead of []uuid.UUID and [][]byte). This shows the expected behavior (I see 3 distinct values instead of the last value repeated 3 times), but it doesn't actually solve my problem.
  2. Set only the last element (put the idBytes[i] = id[:] inside an if i == len(ids) - 1 block). This sets only the last element (the first two elements remain nil).

答案1

得分: 5

考虑以下两个事实:

  • id 的类型是 UUID,它是 [16]byte 类型。
  • 循环变量在每次迭代时都会被覆盖。

因此,在 for 循环的所有迭代中,只有一个 id 实例被分配和共享。由于 id 是一个数组(而不是切片),每个 UUID 的内容都会被复制到 id 中。所有的切片 id[:] 都指向相同的共享底层字节数组,当循环结束时,该数组中包含了 id 的最新内容。

修复方法如下:

idBytes[i] = ids[i][:]

这将为每个 UUID 创建单独的切片。

英文:

Two facts to consider:

  • id is of type UUID, which is [16]byte.
  • Loop variables a overwritten at each iteration

Thus, there is only one instance of id is allocated and shared between all iterations of the for loop. Since id is an array (not a slice), contents of each UUID are copied to id. All the slices id[:], thus, point to the same shared underlying byte array, which, when the loop ends, contains the latest contents of id.

To fix:

idBytes[i] = ids[i][:]

which will create separate slices for each UUID.

huangapple
  • 本文由 发表于 2022年1月14日 03:36:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/70702149.html
匿名

发表评论

匿名网友

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

确定