Go 语言中的指针是变量的内存地址的引用,指针存储的是其他变量的地址,可以用来间接操作变量的值。与其他编程语言相比,Go 的指针相比 C 语言更加安全,因为 Go 不支持指针运算(如指针加减等)。
1. 指针基础
在 Go 中,指针是一个变量,它保存另一个变量的内存地址。通过指针,你可以访问该地址上的值。
1.1 定义指针
Go 中通过 * 来声明指针类型,指针的类型是它所指向变量的类型。
var ptr *int // 声明一个指向 int 类型的指针
*int表示指向int类型的指针。ptr是指针变量,它存储一个内存地址,指向一个int类型的值。
1.2 获取变量的地址
要获取一个变量的地址,可以使用 & 操作符,& 返回的是该变量的内存地址。
x := 58
ptr := &x // ptr 存储 x 的内存地址
fmt.Println(ptr) // 输出指针地址
fmt.Println(*ptr) // 输出指针指向的值,即 58
&x返回x的地址,存储在ptr中。*ptr用于访问ptr指向的值。
2. 解引用指针(Dereferencing)
解引用是通过指针访问其所指向的值。解引用操作符 * 被用于获取指针所指向的值。
x := 58
ptr := &x // ptr 指向 x 的内存地址
fmt.Println(*ptr) // 输出 58,解引用指针,访问指针指向的值
这里,*ptr 表示解引用 ptr,即获取 ptr 指向的值。
3. 指针作为函数参数
在 Go 中,指针常常用于函数参数传递,尤其是当你想让函数修改传入的变量时。传递指针比传递大量数据的副本更高效,特别是对于大对象或结构体。
3.1 传递指针给函数
package main
import "fmt"
func updateValue(ptr *int) {
*ptr = 100 // 修改指针指向的值
}
func main() {
x := 58
fmt.Println("Before:", x) // 输出:Before: 58
updateValue(&x) // 传递 x 的地址
fmt.Println("After:", x) // 输出:After: 100
}
在上述例子中,updateValue 函数通过指针修改了 x 的值。
4. 指针与数组、切片
指针常常与数组和切片一起使用。指针可以直接指向数组或切片中的元素,操作它们的值。
4.1 指向数组
指针可以指向数组的元素,通过指针间接修改数组的内容:
arr := [3]int{1, 2, 3}
ptr := &arr[0] // 指向数组的第一个元素
*ptr = 100
fmt.Println(arr) // 输出:[100 2 3]
4.2 指向切片
切片本身就是一个指向底层数组的引用,可以通过切片的指针来修改底层数组:
arr := []int{1, 2, 3}
ptr := &arr[0] // 指向切片的第一个元素
*ptr = 100
fmt.Println(arr) // 输出:[100 2 3]
5. new 和 make 与指针
Go 提供了 new 和 make 两个内建函数来创建对象,它们与指针相关,但用途有所不同。
5.1 new 函数
new 用于分配内存并初始化为零值,返回一个指向该内存的指针。
ptr := new(int) // 创建一个指向 int 类型的指针
fmt.Println(*ptr) // 输出:0,因为 new 初始化为零值
*ptr = 58
fmt.Println(*ptr) // 输出:58
new(int)创建了一个指向int类型的指针,内存被初始化为零值。
5.2 make 函数
make 用于创建切片、映射(map)和通道(channel),它返回的是切片、映射或通道,而不是指针。与 new 不同,make 不返回一个指向新对象的指针。
slice := make([]int, 5) // 创建一个长度为 5 的切片
fmt.Println(slice) // 输出:[0 0 0 0 0]
make 返回一个初始化过的切片,映射或通道,而 new 返回的是指向零值的指针。
6. 指针的零值
指针的零值是 nil,表示该指针没有指向任何有效的内存地址。
var ptr *int // ptr 默认为 nil
fmt.Println(ptr) // 输出:<nil>
如果你尝试解引用一个 nil 指针,Go 会抛出运行时错误(panic)。
7. 指针的用途总结
- 传递大对象:通过指针传递对象可以避免复制大量数据。
- 函数修改参数:通过传递指针,函数可以修改调用者的变量。
- 内存管理:指针用于动态内存分配,
new可以用于创建指针。 - 切片与数组:指针常用于操作切片和数组。
8. 指针总结
- 指针是存储内存地址的变量,可以用来间接访问和修改值。
- Go 中的指针可以通过
*获取指针所指向的值,通过&获取变量的内存地址。 - 指针是函数参数传递时修改数据的常见方式,尤其用于传递大数据结构。
- Go 使用
new和make来分配内存和创建对象,但它们有不同的用途和行为。