在Go中,通过指针传递结构体可实现多函数共享并实时修改同一对象;因默认值传递会复制副本,而指针传递使所有函数操作同一内存地址,需注意nil检查、并发安全及避免返回局部变量指针。

在 Go 中,通过指针传递结构体或自定义类型的变量,是实现多函数操作同一对象、共享数据的最常用且高效的方式。关键在于:传指针,而非值;所有函数操作的是同一块内存地址上的数据。
为什么用指针而不是值传递?
Go 默认按值传递(copy)。如果传结构体值,每个函数收到的是独立副本,修改不会影响原始数据。而传指针(*T),所有函数都指向同一块内存,自然实现“共享”和“实时同步”。
例如:
type Counter struct{ Val int }
func increment(c Counter) { c.Val++ } // 修改无效:只改副本
func incrementPtr(c *Counter) { c.Val++ } // 修改生效:改原值
基本写法:定义结构体 + 指针参数 + 多函数协作
以一个简单的配置管理器为例,多个函数共同读写同一配置实例:
立即学习“go语言免费学习笔记(深入)”;
- 定义结构体(如 Config)
- 初始化时用 &Config{...} 获取指针
- 所有操作函数接收 *Config 类型参数
- 函数内部直接通过 c.Field = ... 修改字段(无需解引用 *c)
注意事项与常见陷阱
指针共享虽方便,但需注意以下几点:
- nil 指针调用会 panic:使用前建议检查(如 if c == nil { return })
- 并发不安全:多个 goroutine 同时读写同一指针对象时,需加锁(sync.Mutex)或使用原子操作
- 不要返回局部变量的指针:Go 的栈变量在函数返回后可能被回收,但编译器通常会逃逸分析并自动分配到堆上;不过仍应避免显式取地址(如 &x,其中 x 是短生命周期局部变量)
- 切片、map、channel 本身已含指针语义,传值即可共享底层数据,一般无需额外取地址(除非你要修改其头信息,如长度/容量)
实用示例:带状态的计数器管理
下面是一个完整可运行的小例子:
type Counter struct {
Val int
Name string
}
func (c *Counter) Add(n int) { c.Val += n }
func (c *Counter) Reset() { c.Val = 0 }
func (c *Counter) Print() { fmt.Printf("%s: %d\n", c.Name, c.Val) }
func main() {
c := &Counter{Name: "requests"}
c.Add(5)
c.Print() // requests: 5
anotherFunc(c) // 传同一指针
c.Print() // requests: 12
}
func anotherFunc(c *Counter) {
c.Add(7)
}
所有函数操作的都是 c 所指向的同一个 Counter 实例。










