func TestXxxx(t *testing.T) {
var b = make([]byte, 128, 512)
rand.Read(b)
b1 := slices.Clone(b)
b = append(b[:1], b...)
b2 := b[1:]
require.Equal(t, b1, b2)
ptr := uintptr(unsafe.Pointer(unsafe.SliceData(b)))
ptr2 := uintptr(unsafe.Pointer(unsafe.SliceData(b2)))
require.Equal(t, ptr+1, ptr2)
}
第一步:把 b[0]放入 b[1], 这没问题
第二步:把 b[1]放入 b[2], 可是这是的 b[1]在第一步被覆盖了,这样推导下去,整个 b[i]都会变为 b[0] ?
![]() |
1
MoYi123 181 天前
我觉得大概率是编译成 memmove 了.
|
![]() |
3
my3157 181 天前
和前面的没啥关系, b 和 b2 本来就是引用了同一个底层数组的不同位置而已
b = append(b[:1], b...) b2 := b[1:] |
![]() |
4
lasuar 181 天前
不明白为什么产生问题。。
|
![]() |
5
kandaakihito 181 天前
额。。。?我是建议楼主先去看看 slice 的结构体相关的八股文,看完就理解了。
简单来说,此时 b 和 b2 指向的切片内存地址是同一块,你这上面的操作全都在同一段地址上进行。 |
![]() |
6
ns09005264 181 天前
只是把数组 b 的第一个元素移动到最后,完了以后在数组 b 上新创建了切片 b2 ,只比数组 b 少了第一个元素。
后面用 SliceData 获取数组底层的第一个元素指针,数组 b 的指针+1 后就跑到底层的第二个元素指针,切片 b2 的第一个元素指针就是数组 b 的第二个元素。 |
![]() |
7
lysShub OP 楼上几个题也不读,正是因为 slice 的数据是指针引用才会有这个问题
|
![]() |
8
lysShub OP 实际证明,append(v, slice...) 使用 memmv 不仅是出于性能, 为了正确性也必须这么做。
如果把它编译为 for 循环结果就是错误的 func TestZzzzz(t *testing.T) { var b = make([]byte, 128, 512) rand.Read(b) b1 := slices.Clone(b) b2 := b[:1] { // append for _, e := range b { b2 = append(b2, e) } } b2 = b2[1:] require.Equal(t, b1, b2) } |
![]() |
9
my3157 181 天前 ![]() |
![]() |
10
ns09005264 180 天前
你的疑惑似乎都是切片的 append 带来的,可以找找切片的详细资料看看。
``` var b = make([]byte, 10, 10) b2 := b[1:2] // 新切片从 b 的位置 1 开始,到 1 结束,长度只有 1, 但是容量是 b 的容量减开始的位置 1 等于 9 fmt.Println("b: ", b) // [0 0 0 0 0 0 0 0 0 0] // b2 追加新元素,但容量是 10-1=9 ,长度是 1, 不触发扩容,改变了原切片 b 的第三元素 b2 = append(b2, 7) fmt.Println("b: ", b) // [0 0 7 0 0 0 0 0 0 0] // b3 容量是 1,长度是 1, 改变 b3 第一个元素会影响原切片 b 。 b3 := b[9:] b3[0] = 6 b3 = append(b3, 8) fmt.Println("b: ", b) // [0 0 7 0 0 0 0 0 0 6] // 由于 b3 上面追加了新元素,触发扩容,b3 开辟了新空间,和原切片没有关系了,改变第一个元素不影响原切片 b3[0] = 5 fmt.Println("b: ", b) // [0 0 7 0 0 0 0 0 0 6] ``` |