Go中函数参数默认值传递,但可通过指针实现修改原值:结构体指针避免拷贝并支持修改字段;数组指针需严格匹配长度;切片因含底层指针而天然支持元素修改,更常用且灵活。

在 Go 中,函数参数默认是值传递,但通过指针可以实现类似“引用传递”的效果,让函数能修改原始结构体或数组的内容。关键不是“引用传递”(Go 没有引用类型),而是传递指向原数据的地址,从而间接操作原值。
结构体指针参数:避免拷贝,支持修改
结构体较大时,传值会复制全部字段,开销高;传指针只复制 8 字节地址(64 位系统),且允许函数内修改原结构体字段。
示例:
type User struct {
Name string
Age int
}
func updateName(u *User, newName string) {
u.Name = newName // 直接修改原始结构体
}
func main() {
u := User{Name: "Alice", Age: 30}
updateName(&u, "Bob")
fmt.Println(u.Name) // 输出 "Bob",原变量已被修改
}
注意:
- 函数签名中用 *User 表示接收结构体指针;
- 调用时用 &u 取地址;
- 方法接收者也常用指针(如 func (u *User) SetAge(a int)),否则无法修改原值。
数组指针参数:明确传递固定长度数组
Go 中数组是值类型,长度是其类型的一部分(如 [3]int 和 [5]int 是不同类型)。传数组指针可避免拷贝,也能修改原数组元素。
立即学习“go语言免费学习笔记(深入)”;
示例:
func doubleArray(arr *[4]int) {
for i := range arr {
arr[i] *= 2
}
}
func main() {
a := [4]int{1, 2, 3, 4}
doubleArray(&a)
fmt.Println(a) // [2 4 6 8]
}
说明:
- *[4]int 是指向长度为 4 的 int 数组的指针;
- 必须匹配长度,不能用 *[5]int 接收;
- 若需灵活长度,应使用切片([]int)——它本身包含指向底层数组的指针、长度和容量。
切片作为参数:更常用、更灵活的“类引用”方式
虽然切片不是指针类型,但它内部含指针,所以传切片参数时,函数可修改其底层数组元素(但不能改变原切片的长度或容量,除非返回新切片)。
示例:
func multiplyByTwo(s []int) {
for i := range s {
s[i] *= 2
}
// s = append(s, 99) // 这行不会影响调用方的 s 长度/容量
}
func main() {
data := []int{1, 2, 3}
multiplyByTwo(data)
fmt.Println(data) // [2 4 6] —— 元素被修改了
}
要点:
- 切片传参无需取地址(data 即可),因其本身已携带底层数据地址;
- 若需扩容并让调用方感知变化,函数应返回新切片:func grow(s []int) []int;
- 大多数场景下,优先用切片而非数组指针,更符合 Go 习惯。
何时用指针?看需求三原则
- 需要修改原始结构体或数组内容 → 用指针参数
- 结构体较大(比如含大字段或嵌套结构)→ 用指针避免拷贝
- 统一接口或方法集要求(如实现某个 interface)→ 常需指针接收者
- 小结构体(如两个 int)或只读访问 → 传值更清晰、无副作用
不复杂但容易忽略:Go 没有隐式引用,一切显式——想改原值,就传指针;想安全只读,就传值或切片(注意切片仍可改底层数组)。










