Go语言指针使用场景及示例

Go语言指针使用场景及示例 #

在 Go 语言中,指针的使用场景主要集中在以下几个方向。以下是具体场景和示例:


1. 修改函数外部的变量值 #

当函数需要修改外部传入的变量时,必须使用指针。如果直接传递值,函数内部修改的是副本,外部变量不会改变。

func modifyValue(val *int) {
    *val = 100 // 修改指针指向的值
}

func main() {
    x := 42
    modifyValue(&x) // 传递 x 的地址
    fmt.Println(x)  // 输出 100
}

2. 避免大对象复制,提升性能 #

传递大型结构体时,使用指针可以避免内存拷贝,提升效率。

type BigStruct struct {
    data [1e6]int // 占用约 4MB 内存
}

func processLargeStruct(s *BigStruct) {
    // 操作结构体指针,避免复制整个结构体
}

func main() {
    big := BigStruct{}
    processLargeStruct(&big) // 传递指针而非整个结构体
}

3. 方法需要修改接收者状态 #

如果结构体方法需要修改自身字段,必须使用指针接收者。

type Counter struct {
    count int
}

// 指针接收者方法:可以修改结构体内部状态
func (c *Counter) Increment() {
    c.count++
}

func main() {
    c := Counter{}
    c.Increment()
    fmt.Println(c.count) // 输出 1
}

4. 实现链表、树等数据结构 #

指针用于构建动态数据结构中的节点关系。

type Node struct {
    value int
    next  *Node // 指向下一个节点的指针
}

func main() {
    head := &Node{value: 1}
    head.next = &Node{value: 2} // 链表节点通过指针连接
}

5. 动态分配对象,避免返回副本 #

工厂函数返回指针,确保操作同一对象。

type Config struct {
    Timeout int
}

func NewConfig() *Config {
    return &Config{Timeout: 30} // 返回指针
}

func main() {
    cfg := NewConfig()
    cfg.Timeout = 60 // 修改同一对象
}

6. 接口需要操作可变对象 #

某些接口(如 io.Writer)要求指针接收者,确保数据持久化。

type Buffer struct {
    data []byte
}

// 实现 io.Writer 接口的 Write 方法
func (b *Buffer) Write(p []byte) (n int, err error) {
    b.data = append(b.data, p...)
    return len(p), nil
}

func main() {
    var buf bytes.Buffer
    fmt.Fprintf(&buf, "Hello") // 必须传递指针
}

关键区别总结 #

场景 使用指针 不使用指针
修改变量 ✅ 生效 ❌ 无效(副本)
大对象传递 ✅ 高效 ❌ 内存拷贝
方法修改接收者 ✅ 必须 ❌ 无法修改原对象
动态数据结构 ✅ 必须 ❌ 无法链接节点

合理使用指针可以在性能和功能上带来显著优势,但需注意避免空指针(nil)引发的运行时错误。