Go中声明并初始化指针变量需用*T声明类型,再通过&x获取已存在变量地址,如x := 42; p := &x;不可直接赋值字面量或对未寻址值取地址,未初始化指针默认为nil,解引用前须判空。

怎么声明和初始化一个指针变量
Go 中指针变量用 * 声明,但必须指向一个已存在的变量地址,不能直接“new”出空指针(除非显式赋值为 nil)。常见错误是写成 var p *int = 10——这会编译失败,因为右边不是地址。
正确做法是先定义变量,再用取地址符 & 获取其地址:
var x int = 42 var p *int = &x
也可以一步完成:
y := 100 p := &y
-
*int表示“指向 int 的指针”,不是“解引用操作”;解引用发生在使用时,比如*p - 未初始化的指针默认值是
nil,访问*nil会 panic:invalid memory address or nil pointer dereference - 指针类型不支持算术运算(如
p++),这点和 C 不同
什么时候该传指针而不是值
核心判断依据是:是否需要函数内修改原变量,或是否想避免复制大对象。Go 函数参数永远是传值,所以传结构体或 slice 时,若只传值,函数内改的是副本。
立即学习“go语言免费学习笔记(深入)”;
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
例如:
func increment(x int) { x++ } // 对原变量无影响
func incrementPtr(p *int) { *p++ } // 能改原始值
- 传
*struct{...}比传整个 struct 更省内存和 CPU,尤其字段多或含大字段(如[]byte)时 - slice、map、channel 本身是引用类型,传它们的值已经包含底层数据的间接访问能力,一般不需要额外加指针,除非你真要修改 slice header(比如扩容后想让调用方看到新底层数组)
- 方法接收者用指针(
func (s *MyStruct) Do())才能修改结构体字段;值接收者(func (s MyStruct) Do())只能读
如何安全地解引用指针
解引用前必须确认指针非 nil,否则运行时 panic。这不是编译期能检查的,得靠逻辑保证或显式判断。
典型易错场景:函数返回指针但可能为 nil,比如 json.Unmarshal 解析失败时某些字段指针仍为 nil,直接 *p 就崩。
- 总是先判空:
if p != nil { use(*p) } - 如果业务上允许默认值,可用三元风格(Go 没三元运算符,得写 if):
val := 0 if p != nil { val = *p } - 用
==或!=和nil比较是安全的;但不能对nil指针做*p == 0这类操作
指针和 new()、make() 的区别
new(T) 返回 *T,分配零值内存并返回其地址;make(T, args) 只用于 slice/map/channel,返回的是值(不是指针),但内部已初始化好底层结构。
比如:
p1 := new(int) // p1 是 *int,*p1 == 0 s1 := make([]int, 5) // s1 是 []int(不是 *[]int),len(s1)==5
-
new(MyStruct)返回*MyStruct,字段全为零值;等价于var t MyStruct; return &t -
make不接受自定义类型(除非是别名的 slice/map/channel),也不能用于普通 struct;想初始化带字段的 struct,用字面量:&MyStruct{Field: 1} - 不要用
new([]int)代替make([]int, n):前者返回*[]int(即指向 slice header 的指针),但 header 本身未初始化,*p是零 slice,长度容量都为 0,几乎没用
nil 检查,尤其是跨包调用或处理 JSON/DB 数据时,指针来源不可控,一疏忽就 panic。

















