1 简介
在 go社区有句话是: 一切都是值传递, PASS BY VALUE.
当我们传递一个内存地址时,我们传递了一个值
与 C 系列中的所有语言一样,Go 中的所有内容都是通过值传递的。
也就是说,函数总是获取所传递事物的副本,就好像有一个赋值语句将值分配给参数一样。
例如,将 int 值传递给函数会复制 int,传递指针值会复制指针,但不会复制它指向的数据。

本文举例依次说明这几种常见场景。
2 指针的示例
- 指针引用
该代码使 b 成为指向存储 int 的内存地址的指针,b 的类型为 "int pointer"
arduino
其中 *int -- * 是类型的一部分 -- b 是 *int 类型
代码示例
css
a := 43
fmt.Println(a)
fmt.Println(&a)
var b = *&a
fmt.Println(b)
fmt.Println(&b)
- ** 取消引用**
b 是 int 指针;
b 指向存储 int 的内存地址
要查看该内存地址中的值,请在 b 前面添加一个 * 这称为取消引用,在这种情况下,* 是运算符。
go
a := 43
fmt.Println(a) // 43
fmt.Println(&a) // 0xc0000180a8
fmt.Println(*&a) // 43 取消引用
var b = &a
fmt.Println(b) // 0xc0000180a8
fmt.Println(*b) // 43
fmt.Println(&b) // 0xc000006030
fmt.Println(*&b) // 0xc0000180a8
另一个例子很有用, 我们可以传递一个内存地址而不是一堆值(我们可以传递一个引用) 然后我们仍然可以更改存储在该内存地址中的任何内容的值 这使我们的程序性能更高 我们不必传递大量数据 我们只需要传递地址
go
a := 43
fmt.Println(a) // 43
fmt.Println(&a) // 0x20818a220
var b = &a
fmt.Println(b) // 0x20818a220
fmt.Println(*b) // 43
*b = 42 // b 修改了该地址上的值,改为42
fmt.Println(a) // 42
- 值传递时函数不会改变原参数的值
参数x 传递到 其他函数中 不会改变 参数x的值
go
func zero(z int) {
z = 0
}
func main() {
x := 5
zero(x) // 参数 传递到 其他函数中 不会改变 参数的值
fmt.Println(x) // x is still 5
}
- 值传递时使用指针修改原参数的值
参数x 的地址,被传递到函数中, 函数中取消了引用,并改变 传入参数的值
go
func zero(z *int) {
fmt.Println("from function zero ", z) //0xc00000a0c8
*z = 0 //指针加指针 指向了原值
}
func main() {
x := 5
fmt.Println(&x) //0xc00000a0c8
zero(&x)
fmt.Println(x) // x 被修改为 0
}
3 零值汇总
在 Go 语言中,变量定义可以是声明的,也可以通过 make 、 new 函数来声明,
区别在于 make 和 new 函数属于显式声明 display declaration(返回变量实例) 和初始化 initialization(new 返回实例的指针地址)。
如果我们声明的变量未显式初始化,则变量的默认值是该类型的零值。

测试代码
go
var (
a [2]int32
iface interface{}
it int32
ft float32
ct chan int
st string
strct struct{}
sl []int32
mp map[int]int
pt *int
fct func()
)
fmt.Println("zero of array:", a)
fmt.Println("zero of interface:", iface)
fmt.Println("zero of int32:", it)
fmt.Println("zero of float32:", ft)
fmt.Println("zero of chan:", ct)
fmt.Println("zero of string:", st)
fmt.Println("zero of struct:", strct)
fmt.Println("zero of slice:", sl)
fmt.Println("zero of map:", mp)
fmt.Println("zero of *int:", pt)
fmt.Println("zero of fuction:", fct)
输出示例:
go
zero of array: [0 0]
zero of interface: <nil>
zero of int32: 0
zero of float32: 0
zero of chan: <nil>
zero of string:
zero of struct: {}
zero of slice: []
zero of map: map[]
zero of *int: <nil>
zero of fuction: <nil>
4 小结
如果将变量传递给函数,该函数总是会得到它的副本。
因此,调用方和被调用方有两个具有相同值的自变量。
如果被调用方修改了 parameter variable,则效果对调用方不可见。
认识到 Go 总是通过值传递,再加上支持指针的额外表现力,我们就能创建出更清晰的程序。