Golang 切片作为函数参数的“陷阱”
我们知道 Go 中的切片类型是引用类型,直觉来讲在作为函数参数时,如果函数内部修改了切片的值,函数外的也会被修改,但这有个前提:只能修改切片的内容,而不能修改切片它本身。
如果用切片重组或者 append 方法修改了切片的长度或容量,得到的切片就不是原来那个了,因此变化不会反映到函数外。例如:
| func main() { a := [5]int{1, 2, 3, 4, 5} s := a[:] changeSlice(s) fmt.Println(s) }
func changeSlice(s []int) { s = s[:2] s = append(s, 98) }
|
而如果修改了切片的内容,例如其中元素的值,切片的长度跟容量都没有变,会导致函数外部的切片也一起改变
1 2 3 4 5 6 7 8 9 10 11 12 13
| func main() { a := [5]int{1, 2, 3, 4, 5} s := a[:] changeSlice(s) fmt.Println(s) }
func changeSlice(s []int) { s[0] = 4396 }
|
传递切片的指针
如果实在想修改切片,可以传递切片的指针,解引用后进行操作
1 2 3 4 5 6 7 8 9 10 11 12 13
| func main() { a := [5]int{1, 2, 3, 4, 5} s := a[:] changeSlice(&s) fmt.Println(s) }
func changeSlice(s *[]int) { *s = (*s)[:2] *s = append(*s, 4396) }
|
复制切片
如果需要保证切片(或它的关联数组)一定不会被修改,可以将原始切片用内置函数 copy()
复制后操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| func main() { a := [5]int{1, 2, 3, 4, 5} s := a[:] changeSlice(s) fmt.Println(s) }
func changeSlice(s []int) { sCopied := make([]int, len(s)) copy(sCopied, s) sCopied[0] = 4396 sCopied = append(sCopied, 7777) }
|
参考