Go语言中的Value semantics和Pointer semantics是什么意思?在this course中,作者在解释数组和切片的内部结构时多次提到上述术语,但我并不完全理解。
plicqrtu1#
当您调用函数或方法并向其传递参数时,会从值中创建一个副本,并且函数只能访问这些副本。这意味着如果函数试图修改/更改副本,它不会更改原始值。例如:
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参数,调用方的变量(其值已被传递)也不会更改。为了改变它,我们需要改变签名,使其期望一个指针,传递一个指针,并修改所指向的值:
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 }
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 }
double: [2 4] original is: [2 4]
即使我们没有传递指针(is不是指针),调用也修改了它的元素,并且原始切片的值也发生了变化。我们说,尽管在Go语言中所有的东西都是传值的,但是传递的切片都有指针语义,因为如果被调用方修改了元素,它就会反映在原始的切片中。
is
Go语言中的所有东西都是传值的,切片也是,但是切片是一种类似于结构体的数据结构,它包含一个指向底层数组的指针,而底层数组包含了实际的元素,当你传递一个切片时,会产生一个副本,但是只会复制这个切片头(这是片值)。副本将保持相同的指针,指向同一个后台数组。后台数组不被复制。因此当被调用方修改切片的元素时,后台数组的元素也被修改,其与原始切片的后备数组相同。在此阅读更多信息:golang切片是按值传递的吗?有许多类型具有通过指针传递的语义,例如切片、Map、通道。值得注意的是,与切片不同,数组不在一行中,一个数组值意味着它的所有值,传递一个数组会复制它的所有元素。
hujrc8aj2#
与公认的答案相反,实际上切片也有值语义。
func main() { is := []int{1, 2} fmt.Println("double:", len(doubles(is))) fmt.Println("original is:", len(is)) } func doubles(is []int) []int { is = append(is, 2) return is }
问题是一个切片是一个长度和一个数组指针。值语义意味着接收该指针的一个浅副本。因此,元素是共享的,但长度和指针不是。如果你做了足够多的修改来调整内部数组的大小,元素将不再是共享的。
2条答案
按热度按时间plicqrtu1#
当您调用函数或方法并向其传递参数时,会从值中创建一个副本,并且函数只能访问这些副本。
这意味着如果函数试图修改/更改副本,它不会更改原始值。
例如:
此输出(在Go Playground上尝试):
即使
double()
修改了它的i
参数,调用方的变量(其值已被传递)也不会更改。为了改变它,我们需要改变签名,使其期望一个指针,传递一个指针,并修改所指向的值:
此输出(在Go Playground上尝试):
所以如果我们传递了一些东西,我们希望原始值不会因为传递的值被修改而改变,除非我们传递了一个指向它的指针。
例如:
此输出(在Go Playground上尝试):
即使我们没有传递指针(
is
不是指针),调用也修改了它的元素,并且原始切片的值也发生了变化。我们说,尽管在Go语言中所有的东西都是传值的,但是传递的切片都有指针语义,因为如果被调用方修改了元素,它就会反映在原始的切片中。
推理
Go语言中的所有东西都是传值的,切片也是,但是切片是一种类似于结构体的数据结构,它包含一个指向底层数组的指针,而底层数组包含了实际的元素,当你传递一个切片时,会产生一个副本,但是只会复制这个切片头(这是片值)。副本将保持相同的指针,指向同一个后台数组。后台数组不被复制。因此当被调用方修改切片的元素时,后台数组的元素也被修改,其与原始切片的后备数组相同。
在此阅读更多信息:golang切片是按值传递的吗?
有许多类型具有通过指针传递的语义,例如切片、Map、通道。
值得注意的是,与切片不同,数组不在一行中,一个数组值意味着它的所有值,传递一个数组会复制它的所有元素。
hujrc8aj2#
与公认的答案相反,实际上切片也有值语义。
问题是一个切片是一个长度和一个数组指针。值语义意味着接收该指针的一个浅副本。因此,元素是共享的,但长度和指针不是。如果你做了足够多的修改来调整内部数组的大小,元素将不再是共享的。