Go语言指针详解:地址、取值与new/make区别
Go语言的指针操作简单但强大,掌握取地址符(&)和解引用符(*)是核心。本文从基础概念出发,通过完整代码演示指针变量的创建与使用,解析函数传参时的值传递问题,并深入剖析内存分配机制中make与new的本质区别及常见错误排查。
1. 什么是Go语言的指针
在Go语言中,指针变量存储的是另一个变量的内存地址。与普通C或C++不同,Go的指针不支持算术运算(如加减偏移),其核心优势在于能够直接访问和修改变量的值,从而避免在大对象传递时产生昂贵的数据拷贝开销。
掌握指针需要明确三个关键概念:
- 指针地址:变量在内存中的实际位置。
- 指针类型:指针本身的数据类型,如
*int指向整型。 - 指针取值:根据地址获取变量存储的值。
操作中只需记住两个符号:&用于获取变量地址,*用于根据地址取值。
2. 指针地址与指针类型
Go语言中的一切变量在运行时均拥有唯一的内存地址。对于基本数据类型(如int, string, float, bool)以及数组和结构体,都有对应的指针类型。
以下代码展示了如何定义一个整型变量并获取其指针:
package main
import "fmt"
func main() {
a := 10 /* 声明实际变量 */
ip := &a /* 指针变量ip存储a的地址 */
// 输出a的直接地址
fmt.Printf("a 变量的地址是: %x\n", &a)
// 输出指针ip中储存的地址值
fmt.Printf("ip 变量储存的指针地址: %x\n", ip)
// *ip 代表对ip进行解引用,即取出该地址里的值
fmt.Printf("*ip 变量的值: %d\n", *ip)
}
运行结果如下:
a 变量的地址是: 0xc000010200
ip 变量储存的指针地址: 0xc000010200
*ip 变量的值: 10
在该示例中,a是类型为int的变量,而ip被赋值为&a,因此ip的类型自动推断为*int。
这种内存关系的可视化表现如下:
3. 指针取值与函数传参
获取指针后,可以通过*操作符来读取或修改内存中的数据。这一特性在函数传参时尤为关键。默认情况下,Go语言采用“值传递”(即值拷贝),这意味着在函数内部修改参数不会影响原始变量。
若要修改外部变量,必须传递变量的指针:
package main
import "fmt"
func main() {
x := 2
mod1(x) // 传入值,x 保持为 2
fmt.Println(x)
mod2(&x) // 传入指针,x 变为 1024
fmt.Println(x)
}
// 仅接收副本,无法改变主调函数的变量
func mod1(x int) {
x = 1024
}
// 接收指针,通过解引用修改原始内存
func mod2(x *int) {
*x = 1024
}
4. Go中的内存分配:new与make
在处理指针时,常会涉及内存初始化关键字new和make,二者虽然都涉及内存分配,但用途有严格区分。
第1步:使用 new 分配内存
new(Type)函数会为Type类型的零值分配一块内存空间,并返回指向该内存的*Type指针。
package main
import "fmt"
func main() {
a := new(int) // 返回 *int 类型
b := new(bool)
fmt.Printf("%T\n", a) // 输出: *int
fmt.Printf("%T\n", b) // 输出: *bool
// 指针指向的初始值是类型零值
fmt.Println(*a) // 0
fmt.Println(*b) // false
}
第2步:使用 make 初始化引用类型
make仅适用于内置引用类型:slice(切片)、map(映射)和chan(通道)。它的返回值就是这三个类型本身,而非它们的指针。
package main
import "fmt"
func main() {
var user map[string]int
// 必须使用 make 分配内存,否则 user 仍为 nil
user = make(map[string]int, 10)
user["age"] = 18
fmt.Println(user) // map[age:18]
}
核心区别小结
- 返回值:
new返回指针*Type;make返回类型本身。Type。 - 适用对象:
new用于所有类型的内存分配;make专用于 slice, map, channel 的内部数据结构初始化。
5. 常见问题排查:Nil Pointer Dereference
初学者常遇到panic: runtime error: invalid memory address or nil pointer dereference报错。这通常发生在使用未分配内存的指针或未初始化的引用类型时。
package main
import "fmt"
func main() {
var a *int
// 错误示范:a是nil指针,不能直接赋值
*a = 100
var user map[string]int
// 错误示范:user未make,是nil map,不能直接赋值
user["age"] = 18
}
**原因**:引用类型(如map)和空指针必须先进行内存分配。解决方法是给指针赋予有效地址(使用new或指向已存在变量),并在使用map、slice前调用make。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













