跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何在Golang中理解指针与值的区别 Go语言内存地址与数据存储解析

Go中参数均为值传递,传指针实为传指针副本,故函数内重赋指针值不影响外部;修改指向内容需*p = newVal,改指针本身需**int或返回新指针。 为什么
&
取地址后传参,函数里改了值,外面没变? 因为 Go 里所有参数都是值传递——包括指针本身。你传的是指针变量的副本,它指向的地址没错,但如果你在函数里给这个指针变量重新赋值(比如
p = &x
),外面那个指针变量完全不受影响。 常见错误现象:
func modify(p *int) { p = &someLocalVar }
,调用后原指针没变;或者误以为“传了指针就能改指针变量本身”,其实只能改它指向的内存内容。 想修改原始变量的值 → 用
*p = newValue
想让指针变量指向新地址 → 必须传
**int
(指针的指针),或返回新指针 结构体字段赋值时,
s.field = 1
和
(*ps).field = 1
等价,Go 允许省略括号
new()
和
make()
到底该用哪个?
new(T)
只分配零值内存,返回
*T
;
make(T, args...)
只用于
slice
、
map
、
chan
,返回的是类型本身(不是指针),且完成初始化(比如 slice 的底层数组、map 的哈希表)。 用错的典型表现:
new([]int)
返回
*[]int
,但这个 slice 是 nil,不能直接
append
;
make([]*int, 5)
创建长度为 5 的 slice,每个元素是
*int
类型,但都为 nil,需单独赋值。 立即学习 “ go语言免费学习笔记(深入) ”; 要一个可读写的空 slice/map/chan → 用
make
只想要一个指向零值的指针(比如初始化 struct 指针)→ 用
new
,但更惯用
&T{}
new(string)
返回
*string
,值是
""
;
make(string, 5)
报错:string 不支持
make
struct 字段带
*
和不带有什么区别? 区别在内存布局和赋值行为。带
*
的字段存的是地址,不带的是实际数据拷贝。这直接影响深浅拷贝、内存占用、nil 判断和并发安全。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 使用场景举例:一个大 struct(比如含 1MB 字节数组)作为字段,如果用值类型,每次赋值或传参都复制 1MB;改成
*[1024*1024]byte
,只复制 8 字节地址,但要注意判空和生命周期管理。 字段是
sync.Mutex
→ 不能是指针,否则复制后两把锁不独立,会 panic 字段是
*os.File
→ 可以,因为文件句柄需要共享,且
File
本身不可拷贝 JSON 解析时,
json.Unmarshal
对
*T
字段要求目标非 nil,否则跳过赋值 怎么快速判断某个变量该不该用指针传参? 看三个条件是否满足任意一个:是否需要修改原值、是否类型过大、是否属于不可比较/不可拷贝类型(如
sync.WaitGroup
)。满足就传指针;否则优先用值传递——Go 的小类型(
int
、
string
、小 struct)拷贝成本极低,且更清晰安全。 性能影响常被高估:64 位系统上,
int64
和
*int64
都占 8 字节;但指针多一次内存寻址,且可能触发逃逸分析导致堆分配。
func process(s string)
比
func process(s *string)
更快、更安全,除非你要修改
s
本身(字符串不可变,所以基本不用)
func save(u User)
如果
User
有 20 个字段,建议用
*User
;但如果只有
id int
和
name string
,值传更干净 接口类型变量(如
io.Reader
)本身就是指针语义,传参无需额外加
*
最容易被忽略的是:指针字段的零值是
nil
,访问前必须检查,而值字段天然可读写。这点在解码、初始化、测试 mock 时经常出问题。

相关文章