Go中的“值语义”和“指针语义”是什么意思?

问题描述 投票:4回答:1

Go中的值语义和指针语义是什么意思?在this course中,作者在解释数组和切片的内部时,曾经多次提及上述术语,我无法完全理解它。

go data-structures pass-by-value pass-by-pointer
1个回答
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不是指针),calle也修改了它的元素,并且原始切片的值也发生了变化。

我们说即使在Go中,一切都是按值传递的,传递切片也有指针语义,因为如果被调用者修改元素,它将反映在原始元素中。

推理

Go中的所有内容都按值传递,也是切片。但是切片是在类似于hood-struct的数据结构下,它包含指向保存实际元素的底层数组的指针。当您传递切片时,会复制一个副本,但只会复制此切片标头(这是切片值)。副本将保持相同的指针,指向相同的后备阵列。不复制后备阵列。因此,当被调用者修改切片的元素时,将修改后备数组的元素,这与原始切片的后备数组相同。

在这里阅读更多相关信息:Are golang slices pass by value?

有许多类型通过指针语义传递,例如切片,贴图,通道。

值得注意的是 - 与切片不同 - 数组不在行中,数组值表示其所有值,并且传递数组会复制其所有元素。

© www.soinside.com 2019 - 2024. All rights reserved.