Go中的值语义和指针语义是什么意思?在this course中,作者在解释数组和切片的内部时曾经多次提到上述术语,而我无法完全理解。
答案 0 :(得分:8)
调用函数或方法并将参数传递给它时,将根据值创建一个副本,该函数只能访问这些副本。
这意味着如果该函数尝试修改/更改副本,则不会更改原始值。
例如:
func main() {
i := 1
fmt.Println("double:", double(i))
fmt.Println("original i:", i)
}
func double(i int) int {
i *= 2
return i
}
这将输出(在Go Playground上尝试):
double: 2
original i: 1
即使double()
修改了其i
参数,调用方的变量(传递了值的变量)也没有改变。
要更改它,我们需要更改签名以期望有一个指针,传递一个指针并修改指向的值:
func main() {
i := 1
fmt.Println("double:", doublep(&i))
fmt.Println("original i:", i)
}
func doublep(i *int) int {
*i *= 2
return *i
}
这将输出(在Go Playground上尝试):
double: 2
original i: 2
因此,如果我们传递一些东西,我们期望如果传递的值被修改,除非传递一个指向它的指针,否则原始值不会改变。
指针语义意味着,即使我们通过“按值”传递某些内容,被调用方仍可以修改“原始”值,就像我们已经将指针传递给它一样。
例如:
func main() {
is := []int{1, 2}
fmt.Println("double:", doubles(is))
fmt.Println("original is:", is)
}
func doubles(is []int) []int {
for i := range is {
is[i] *= 2
}
return is
}
这将输出(在Go Playground上尝试):
double: [2 4]
original is: [2 4]
即使我们没有传递指针(is
不是指针),被调用者仍会修改其元素,并且原始切片的值也会更改。
我们说,即使在Go语言中,所有内容都按值传递,但传递的切片具有指针语义,因为如果被调用者修改了元素,它将反映在原始元素中。
Go中的所有内容都按值传递,也进行切片。但是,切片是在幕后,是类似结构的数据结构,该数据结构包含指向保存实际元素的基础数组的指针。并且,当您传递切片时,将进行复制,但是只会复制此切片标头(这是切片值)。副本将拥有相同的指针,指向相同的后备数组。没有复制后备阵列。因此,当被调用方修改切片的元素时,支持数组的元素也将被修改,这与原始切片的支持数组相同。
在此处详细了解:Are golang slices pass by value?
有许多通过指针语义传递的类型,例如切片,地图,通道。
值得注意的是,与切片不同,数组不在行中,数组值表示其所有值,传递数组会复制其所有元素。