返回

Go 语言中不存在引用传递:深层次剖析值传递的本质

后端

Go 语言中不存在引用传递

Go 语言中从来就不存在所谓的“引用传递”,从来就只有一种变量传递方式,那就是值传递。因为引用传递的前提是存在“引用变量”,但是 Go 语言中从来就没有出现过所谓的“引用变量”。

理解值传递

值传递是指将变量的值从一个变量复制到另一个变量。在这个过程中,两个变量是独立的,互不影响。例如:

package main

func main() {
    var a = 10
    var b = a
    a++
    fmt.Println(a, b) // 输出:11 10
}

在这个例子中,我们定义了两个变量 ab,并通过赋值操作将 a 的值复制到了 b。当我们对 a 的值进行修改时,b 的值不会受到影响。这说明 ab 是两个独立的变量,a 的值的变化不会影响 b 的值。

引用类型的本质

在 Go 语言中,引用类型是指指向其他变量或数据的变量。引用类型本身不存储实际的值,而是存储指向实际值的内存地址。例如:

package main

type Person struct {
    name string
    age  int
}

func main() {
    var p1 = Person{name: "John", age: 30}
    var p2 = p1
    p1.name = "Mary"
    fmt.Println(p1.name, p2.name) // 输出:Mary Mary
}

在这个例子中,我们定义了一个结构体 Person,并通过赋值操作将 p1 的值复制到了 p2。当我们对 p1name 属性进行修改时,p2name 属性的值也会受到影响。这说明 p1p2 指向同一个 Person 结构体,p1Person 结构体的修改也会影响到 p2

但是,需要注意的是,p1p2 仍然是两个独立的变量,p1 的值的变化不会影响 p2 的内存地址。例如:

package main

type Person struct {
    name string
    age  int
}

func main() {
    var p1 = Person{name: "John", age: 30}
    var p2 = p1
    fmt.Println(&p1, &p2) // 输出:0xc00009e0c8 0xc00009e0d0
}

在这个例子中,我们打印了 p1p2 的内存地址,可以看到两个变量的内存地址是不同的。这说明 p1p2 仍然是两个独立的变量,p1 的值的变化不会影响 p2 的内存地址。

理解指针传递

在 Go 语言中,指针变量是指向其他变量或数据的内存地址的变量。指针变量本身不存储实际的值,而是存储指向实际值的内存地址。例如:

package main

func main() {
    var a = 10
    var p = &a
    *p++
    fmt.Println(a, *p) // 输出:11 11
}

在这个例子中,我们定义了一个变量 a 和一个指针变量 p,并通过取地址运算符 &a 的内存地址赋值给了 p。当我们对 *p 的值进行修改时,a 的值也会受到影响。这说明 p 指向 a 的内存地址,*p 的值的变化会影响到 a 的值。

但是,需要注意的是,pa 仍然是两个独立的变量,p 的值的变化不会影响 a 的内存地址。例如:

package main

func main() {
    var a = 10
    var p = &a
    fmt.Println(&a, p) // 输出:0xc00009e0c8 0xc00009e0d0
}

在这个例子中,我们打印了 a 的内存地址和 p 的值,可以看到两个变量的内存地址是不同的。这说明 pa 仍然是两个独立的变量,p 的值的变化不会影响 a 的内存地址。

总结

综上所述,Go 语言中不存在引用传递,只有值传递和指针传递。值传递是指将变量的值从一个变量复制到另一个变量,而指针传递是指将变量的内存地址从一个变量复制到另一个变量。值传递和指针传递都是独立的变量传递方式,互不影响。