Go语言中的slice函数参数传递的本质
2023-09-09 09:01:40
最近在学习Go语言的过程中,发现一个有意思的事情,有的文章说函数调用传参时 slice 是引用传递,有的说是值传递。为什么同一个东西大家会不同认识?为了搞清楚其本质,我进行了以下内容的研究:
问题一、slice是值传递还是引用传递?
根据Go语言官方文档的定义,slice是引用类型,这意味着它存储的是对底层数组的引用。当我们把slice作为函数参数传递时,实际上是把slice的引用传递给了函数。因此,函数内部对slice的任何修改都会反映到原始slice中。
问题二、为什么有的文章说slice是值传递?
因为slice虽然是引用类型,但它在函数调用时却表现得像值类型。这是因为Go语言编译器在函数调用时会对slice进行一次复制,然后把复制后的slice传递给函数。因此,函数内部对复制后的slice的任何修改都不会反映到原始slice中。
示例代码
package main
import "fmt"
func main() {
// 定义一个slice
s := []int{1, 2, 3}
// 把slice作为参数传递给函数
modifySlice(s)
// 打印原始slice
fmt.Println(s) // 输出:[1 2 3]
// 定义一个slice,并使用make函数初始化
s2 := make([]int, 3)
copy(s2, s) // 把s中的元素拷贝到s2中
// 把slice作为参数传递给函数
modifySlice2(s2)
// 打印原始slice
fmt.Println(s2) // 输出:[4 5 6]
}
// 函数修改slice
func modifySlice(s []int) {
s[0] = 4
s[1] = 5
s[2] = 6
}
// 函数修改slice
func modifySlice2(s []int) {
s[0] = 4
s[1] = 5
s[2] = 6
}
在上面的示例代码中,modifySlice
函数接收一个slice作为参数,并在函数内部修改了slice的元素。然后,我们打印原始slice,发现原始slice并没有被修改。这是因为Go语言编译器在函数调用时对slice进行了复制,函数内部对复制后的slice的修改不会反映到原始slice中。
而在modifySlice2
函数中,我们使用了make
函数初始化了一个新的slice,并使用copy
函数把原始slice中的元素拷贝到新的slice中。然后,我们把新的slice作为参数传递给函数,并在函数内部修改了新的slice的元素。然后,我们打印原始slice,发现原始slice被修改了。这是因为copy
函数在把元素拷贝到新的slice时,实际上是把元素的值拷贝到了新的slice中,而不是把元素的引用拷贝到了新的slice中。因此,函数内部对新的slice的修改会反映到原始slice中。
结论
- slice是引用类型,但在函数调用时却表现得像值类型。
- 这是因为Go语言编译器在函数调用时会对slice进行一次复制,然后把复制后的slice传递给函数。
- 函数内部对复制后的slice的任何修改都不会反映到原始slice中。
- 如果想在函数内部修改原始slice,则需要使用
make
函数和copy
函数来创建一个新的slice,然后把新的slice作为参数传递给函数。