Files
cs-note/hzh/GolangStar/Go语言基础/Go语言指针.md
T

3.4 KiB
Raw Blame History

tags, create time
tags create time
go
golang
go基础语法
指针
2026-06-07 15:00

Go 语言指针

概述

指针是存放内存地址的变量。Go 保留了这一底层能力,但做了简化——去掉了指针运算,只保留 &(取地址)和 *(解引用)。本文解释指针的工作原理、new() vs make(),以及何时该用指针。

正文

指针到底是什么?

简单说:指针 = 内存地址。它本身不存储数据,而是指向存储数据的位置。

b := 42           // b 在内存某处存了值 42
ptr := &b         // ptr 存的是 b 的地址(如 0x14000018000)
fmt.Println(*ptr) // 通过地址读取 → 42
*ptr = 100        // 通过地址修改 → b 变成了 100
操作符 含义 示例
&T 取变量的地址 &b → *int
*T 解引用指针 *ptr → 读取/写入指向的值

[!question] ❓ 思考 如果 a := &b,那么 *a = 100 会影响 b 吗?为什么?

创建指针的两种方式

方式一:& 取地址

var ptr *int
b := 3
ptr = &b     // ptr 指向 b 的地址
fmt.Println(*ptr)  // 3

未初始化的指针值为 nil:

var p *int
fmt.Println(p == nil)  // true

方式二:new() 分配零值内存

p := new(int)      // 分配 int 大小的内存,归零,返回 *int
*p = 42
fmt.Println(*p)    // 42

[!note] 📝 new(T) 做了什么?

  1. 分配一块大小为 sizeof(T) 的内存
  2. 将内存清零(零值)
  3. 返回 *T 指向这块内存

等价于 &T{},但后者更常用且可内联初始化。

new() vs make():最常见的混淆

这是 Go 面试必问的问题:

new(T) make(T, ...)
适用类型 所有类型 仅限 slice、map、chan
返回值 *T(指针) T(值本身)
用途 分配零值内存 分配+初始化
// new:只分配,不归零以外的初始化
p := new(int)       // *int,指向 0
s := new([]int)     // *[]int,指向 nil slice(不能直接用!)

// make:分配 + 初始化
sl := make([]int, 3, 5)   // len=3, cap=5 的切片
mp := make(map[string]int) // 可用的空 map
ch := make(chan int, 10)   // 缓冲为 10 的 channel

[!warning] ⚠️ new([]int) 是陷阱 new([]int) 返回的是 *[]int,里面的 slice 头是 nil。对它做 append 会 panic。应该用 make。

结构体与指针

type Point struct {
    X, Y int
}

p := Point{X: 1, Y: 2}
ptr := &p
ptr.X = 10          // Go 自动解引用,等价于 (*ptr).X = 10
fmt.Println(p.X)    // 10 — 原值被修改了

[!tip] 💡 什么时候传指针?

  • 需要修改原值:函数参数传 *T
  • 结构体较大:避免拷贝开销(通常 > 64 字节就值得考虑)
  • slice/map/chan:它们本身就是引用语义,不需要额外加指针

常见误区

[!warning] ⚠️ 不要对 map 元素取地址

m := map[string]int{"a": 1}
p := &m["a"]  // ❌ 编译错误:cannot take address of map element

map 的元素不是稳定的内存位置——扩容时整个数据结构会迁移。

[!info] ℹ️ Go 没有指针运算 Go 去掉了 C 语言的 ptr++、ptr + n 等指针算术。你只能:

  • 取地址 &v
  • 解引用 *p
  • 比较 p == nil

这消除了缓冲区溢出等安全漏洞。