1.6 golang 指针

7 阅读2分钟

1.6 指针

指针的基本概念

指针存储变量的内存地址。Go 的指针比 C 更安全:没有指针运算,有垃圾回收。

package main

import "fmt"

func main() {
    x := 42
    p := &x         // &x 取地址,p 是 *int 类型
    
    fmt.Println(p)  // 0x9867cc14020(内存地址)
    fmt.Println(*p) // 42(解引用,获取值)
    
    *p = 100        // 通过指针修改原变量
    fmt.Println(x)  // 100
    
    // 指针的零值是 nil
    var pp *int
    fmt.Println(pp)         // <nil>
    fmt.Println(pp == nil)  // true
}

值传递 vs 指针传递

Go 中函数参数全部是值传递,传指针实际上是传了地址的拷贝。

// 值传递:函数内修改不影响原变量
func doubleValue(n int) {
    n *= 2
}

// 指针传递:通过指针修改原变量
func doublePointer(n *int) {
    *n *= 2
}

func main() {
    x := 10
    
    doubleValue(x)
    fmt.Println(x) // 10(没变)
    
    doublePointer(&x)
    fmt.Println(x) // 20(变了)
}

结构体与指针

type User struct {
    Name string
    Age  int
}

// 值传递:拷贝整个结构体(大结构体效率低)
func birthdayValue(u User) {
    u.Age++ // 不影响原结构体
}

// 指针传递:只拷贝地址(推荐)
func birthdayPointer(u *User) {
    u.Age++ // 修改原结构体
}

func main() {
    user := User{Name: "Alice", Age: 25}
    
    birthdayValue(user)
    fmt.Println(user.Age) // 25
    
    birthdayPointer(&user)
    fmt.Println(user.Age) // 26
}

new 与 make

func main() {
    // new:分配内存,返回指针,值为零值
    p := new(int)       // *int,值为 0
    fmt.Println(*p)     // 0
    
    u := new(User)      // *User,各字段为零值
    u.Name = "Bob"
    
    // make:只用于 slice、map、channel,返回值(不是指针)
    s := make([]int, 5)
    m := make(map[string]int)
    ch := make(chan int)
    
    _ = s; _ = m; _ = ch
}
函数适用类型返回值
new(T)任意类型*T(指针)
make(T)slice、map、channelT(值)

何时使用指针

// ✅ 需要修改调用者的变量
func reset(p *int) { *p = 0 }

// ✅ 避免大结构体拷贝(通常 > 64 字节考虑用指针)
func processLargeStruct(data *LargeStruct) { ... }

// ✅ 表示"可选"值(nil 代表不存在)
func find(id int) *User { ... } // 返回 nil 表示没找到

// ❌ 小的值类型(int、bool)不需要指针
// ❌ 不需要修改原值时不需要指针

指针安全

func main() {
    // Go 没有指针运算
    // p++ // ❌ 编译错误
    
    // Go 有垃圾回收(GC),不需要手动释放内存
    p := new(int)
    *p = 42
    // 不需要 free(p),GC 会自动回收
    
    // 返回局部变量的指针是安全的(Go 会自动逃逸到堆上)
    pp := createPointer()
    fmt.Println(*pp) // 100
}

func createPointer() *int {
    x := 100
    return &x // ✅ 安全!Go 编译器会将 x 分配到堆上
}

小结

要点说明
&取地址
*解引用 / 指针类型声明
值传递Go 所有传参都是值传递
指针传递传地址的拷贝,可以修改原值
安全无指针运算、有 GC、可返回局部指针