blog
blog copied to clipboard
Go 语言陷阱 - 数组和切片 | Go 语言高性能编程 | 极客兔兔
https://geektutu.com/post/hpg-gotchas-array-slice.html
Go 语言/golang 高性能编程(high performance go),Go 语言进阶教程,Go 语言陷阱(gotchas)。这篇文章介绍了 Go 语言中数组(Array) 和切片(Slice)的常见陷阱和规避方式。例如数组作为参数,修改参数,原数组不会发生改变。
大佬真的牛批,起初知道对slice的修改会影响到原来的slice,就以为添加操作也有可能会被修改。无论slice的长度多少,只要对slice的添加操作都是会生成一个新的slice,原来的slice不受影响。感谢
看完收工
@chocolateszz 你的理解是对的,不同切片维护了 len 和 cap,添加操作,不改变 len 长度以前的底层数组的元素,所以不影响。
@bestgopher 哈哈,后面会增加新的文章,逐步增加难度~
厉害 期待大佬的新文章 受益匪浅~
厉害 期待大佬的新文章 受益匪浅~
@zpng 感谢认可,近期会频繁更新哒~
想到 slice 只要不扩容,就不会重新分配空间,其实可以提前分配好空间,避免在调用的函数内部扩容。但是由于整个 slice
是作为传值传入函数内部的,所以 slice
结构体内部的 len
在函数结束后,依然是原来的长度。
我尝试了手动修改 slice
结构体内部的 len
,算是第三种 foo 函数影响原切片的方法(滑稽 🤣
func foo(a []int) {
a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)
a[0] = 200
}
func main() {
// 提前分配空间,防止扩容修改空间
a := make([]int, 0, 20)
a = append(a, 1, 2)
foo(a)
fmt.Println(a)
// slice struct from https://golang.org/src/runtime/slice.go
pointerOfa := unsafe.Pointer(&a)
pointerSize := unsafe.Sizeof(pointerOfa)
intSize := unsafe.Sizeof(int(0))
internalLengthPointer := (*int64)(unsafe.Pointer(uintptr(pointerOfa) + uintptr(pointerSize)))
internalCapPointer := (*int64)(unsafe.Pointer(uintptr(pointerOfa) + uintptr(pointerSize) + uintptr(intSize)))
fmt.Printf("the internalCapLength: %d, cap(a): %d\n", *internalCapPointer, cap(a))
fmt.Printf("the internalLengthPointer: %d, len(c): %d\n", *internalLengthPointer, len(a))
*internalLengthPointer = 10
fmt.Println("after modify")
fmt.Println(a)
}
output:
[200 2]
the internalCapLength: 20, cap(a): 20
the internalLengthPointer: 2, len(c): 2
after modify
[200 2 1 2 3 4 5 6 7 8]
@kele1997 嗯,这一串操作好 6 ~
大佬这个系列写的挺好的,通过测试对性能有了直观的感受,多多交流
@wsqyouth Thanks♪(・ω・)ノ,多交流~
大佬,文章什么时候再更新?
学到了,学到了
全部看完了,学到了很多
传参时拷贝了新的切片,因此当新切片的长度发生改变时,原切片并不会发生改变。
这里应该是切片容量发生改变时,才会分配新的内存空间,导致函数体中的切片底层指针指向新的空间。如果容量不变,foo函数的作用效果是可以体现在原切片中的。
看完了,受益匪浅
谢谢大佬 看完了 收获颇多
func foo(a []int) { a = append(a, 1, 2, 3, 4, 5, 6, 7, 8) a[0] = 200 }
func main() { a := []int{1, 2} foo(a) fmt.Println(a) }
如果不append的话会影响a的,a是引用类型。归根到底是slice是引用类型,当 len > cap 后会分配新的内存。
博主不更新了吗
看完,求更
大佬牛逼,看完收获颇多
切片是引用传递,在未扩容的情况下,修改原切片长度内的元素会修改原数组,但是一旦扩容后,就类似一个副本,怎么修改都不影响原切片
看完了,学到了好多,谢谢兔兔!