在Golang中,函数调用时参数传递默认采用值传递的方式,也就是会把传入的变量复制一份传递到函数内部,函数内对参数的修改不会影响函数外的原变量。如果要实现函数内修改函数外变量的效果,就需要使用指针来完成。

Golang指针基础概念
指针是一个存储变量内存地址的变量,在Golang中通过&操作符可以获取变量的地址,通过*操作符可以获取指针指向地址的变量值,也可以修改该地址存储的变量值。
比如定义一个整型变量a,获取它的地址赋值给指针变量p,就可以通过p来操作a的值:
package main
import "fmt"
func main() {
var a int = 10
// 获取a的地址赋值给指针p
var p *int = &a
fmt.Println("a的地址:", &a)
fmt.Println("p存储的地址:", p)
fmt.Println("通过p获取a的值:", *p)
// 通过指针修改a的值
*p = 20
fmt.Println("修改后a的值:", a)
}值传递与指针传递的区别
值传递会把变量的副本传入函数,函数内操作的是副本,不会影响原变量;指针传递传入的是变量的地址,函数内通过地址操作的是原变量本身。
下面的示例可以直观看到两种传递方式的差异:
package main
import "fmt"
// 值传递修改函数
func modifyByValue(num int) {
num = 100
fmt.Println("值传递函数内num的值:", num)
}
// 指针传递修改函数
func modifyByPointer(num *int) {
*num = 100
fmt.Println("指针传递函数内num的值:", *num)
}
func main() {
a := 10
fmt.Println("调用值传递函数前a的值:", a)
modifyByValue(a)
fmt.Println("调用值传递函数后a的值:", a)
b := 10
fmt.Println("调用指针传递函数前b的值:", b)
modifyByPointer(&b)
fmt.Println("调用指针传递函数后b的值:", b)
}运行上述代码会输出:
- 调用值传递函数前a的值: 10
- 值传递函数内num的值: 100
- 调用值传递函数后a的值: 10
- 调用指针传递函数前b的值: 10
- 指针传递函数内num的值: 100
- 调用指针传递函数后b的值: 100
可以看到值传递无法修改外部变量,而指针传递成功修改了外部的b变量。
指针修改函数外变量的完整示例
下面是一个更完整的示例,演示如何通过指针修改不同类型的函数外变量:
package main
import "fmt"
// 修改整型变量
func updateInt(num *int) {
*num = *num * 2
}
// 修改字符串变量
func updateString(str *string) {
*str = *str + ",修改后的内容"
}
// 修改结构体字段
type User struct {
Name string
Age int
}
func updateUser(u *User) {
u.Name = "李四"
u.Age = 25
}
func main() {
// 修改整型
num := 5
fmt.Println("修改前num:", num)
updateInt(&num)
fmt.Println("修改后num:", num)
// 修改字符串
str := "原始字符串"
fmt.Println("修改前str:", str)
updateString(&str)
fmt.Println("修改后str:", str)
// 修改结构体
user := User{Name: "张三", Age: 20}
fmt.Println("修改前user:", user)
updateUser(&user)
fmt.Println("修改后user:", user)
}指针使用注意事项
使用指针修改函数外变量时需要注意以下几点:
- 传递指针时需要先确保指针不为空,避免对空指针进行解引用操作,否则会触发panic。
- 不要返回局部变量的指针,因为局部变量在函数执行结束后会被销毁,返回的指针指向的内存可能已经被回收,访问会有不可预期的问题。
- 除非需要修改函数外变量或者传递大对象避免复制开销,否则不需要刻意使用指针,过度使用指针会增加代码的复杂度和维护难度。
指针是Golang中重要的特性,合理使用指针可以解决值传递的局限性,实现函数内外变量的联动修改,但也要注意规避指针使用过程中的常见错误。