2021-10-24
Go语言指针详解
指针(pointer)在Go语言中可以被拆分为两个核心概念:
类型指针,允许对这个指针类型的数据进行修改,传递数据可以直接使用指针,而无须拷贝数据,类型指针不能进行偏移和运算。
切片,由指向起始元素的原始指针、元素数量和容量组成。
要知道几个概念:指针地址、指针类型和指针取值,下面将展开详细说明。
指针地址和指针类型
一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在 32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。当一个指针被定义后没有分配到任何变量时,它的默认值为 nil。指针变量通常缩写为 ptr。
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用在变量名前面添加&
操作符(前缀)来获取变量的内存地址(取地址操作),格式如下:
ptr := &v // v 的类型为 T</pre>
其中 v 代表被取地址的变量,变量 v 的地址使用变量 ptr 进行接收,ptr 的类型为*T
,称做 T 的指针类型,*
代表指针。
package main
import "fmt"
func main() {
var cat int = 123
var dog string = "woshinidie"
fmt.Printf("%p %p",&cat,&dog)
}
打印的结果:0xc00000a0a8 0xc000042230
提示:变量、指针和地址三者的关系是,每个变量都拥有地址,指针的值就是地址。
获取指针的值
当使用&
操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*
操作符,也就是指针取值,
package main
import "fmt"
func main() {
var dog = "woshinidie"
ptr:=&dog
fmt.Printf("type:%T\n",ptr) // 打印ptr的类型
fmt.Printf("address:%p\n",ptr) // 打印ptr的指针地址
value:=*ptr
fmt.Printf("type:%T\n",value) // 取值后的类型
fmt.Printf("value:%s",value) // 指针取值后就是指向变量的值
}
取地址操作符&
和取值操作符*
是一对互补操作符,&
取出地址,*
根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
对变量进行取地址操作使用
&
操作符,可以获得这个变量的指针变量。指针变量的值是指针地址。
对指针变量进行取值操作使用
*
操作符,可以获得指针变量指向的原变量的值。
通过指针修改值
指针不仅可以取值,也可以修改值。
package main
import "fmt"
func main() {
yi:=33
er:=44
swap(&yi, &er)
fmt.Println(yi,er)
}
func swap(a, b *int) {
c := *a
*a = *b
*b = c
}
使用指针变量获取命令行的输入信息
package main
// 导入系统包
import (
"flag"
"fmt"
)
// 定义命令行参数
var mode = flag.String("mode", "", "process mode")
func main() {
// 解析命令行参数
flag.Parse()
// 输出命令行参数
fmt.Println(*mode)
}
由于之前已经使用 flag.String 注册了一个名为 mode 的命令行参数,flag 底层知道怎么解析命令行,并且将值赋给 mode*string 指针,在 Parse 调用完毕后,无须从 flag 获取值,而是通过自己注册的这个 mode 指针获取到最终的值。代码运行流程如下图所示
创建指针的另一种方法——new() 函数
Go语言还提供了另外一种方法来创建指针变量,格式如下:
new(类型)
一般这样写:
str := new(string)
*str = "Go指针"
fmt.Println(*str)
new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。