笔者个人网站:秋码记录
本文已首发于秋码记录:Go 语言中的指针(Let’s Go 九)
说到指针,想必很多人会谈虎色变吧,在c/c++语言中那晦涩难懂的指针,曾几何时,让人望而却步!
虽说,指针操作效率是相当的快,可一旦把握不好,就会造成可怕的错误。
与c/c++语言不同的是,在Go中是不允许进行指针运算的。
1、声明指针
类型 *T 是指向 T 类型值的指针。其默认值为 nil。
var name *type
var p *int
其实,每个变量在运行时,在内存都有属于自己的内存地址,而这个地址就是代表着变量在内存的位置。
与c/c++语言一样,要想获取变量在内存的地址,只需在变量前面加个&即可。
func main() {
v := "https://qiucode.cn"
ptr := &v
}
其中,&v表示取变量v的内存地址,而变量 v 的内存地址又赋值给变量ptr,此时变量ptr类型为*string,称作string的指针类型,* 代表指针。
package main
import "fmt"
func main() {
var age int = 4
v := "https://qiucode.cn"
ptr := &v
fmt.Printf("%p %p", &age, ptr)
}
- 指针的值是带有
0x十六进制前缀的一组数据。

2、获取指针指向的值
当我们使用&操作符对普通变量取地址,在得到变量的指针后,接着使用*操作符对普通变量进行取值,也就是指针取值。
package main
import "fmt"
func main() {
// 准备一个字符串类型
var webSite = "https://qiucode.cn"
// 对字符串取地址, ptr类型为*string
ptr := &webSite
// 打印ptr的类型
fmt.Printf("ptr 的类型: %T\n", ptr)
// 打印ptr的指针地址
fmt.Printf("ptr 指针地址: %p\n", ptr)
// 对指针进行取值操作
value := *ptr
// 取值后的类型
fmt.Printf("value 类型: %T\n", value)
// 指针取值后就是指向变量的值
fmt.Printf("value 指向变量的值: %s\n", value)
}

取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
- 对变量进行取地址操作使用
&操作符,可以获得这个变量的指针变量。 - 指针变量的值是指针地址。
- 对指针变量进行取值操作使用
*操作符,可以获得指针变量指向的原变量的值。
3、指针修改值
指针不仅可以取值,还可以修改值
package main
import "fmt"
// 交换函数
func swap(a, b *string) {
// 取a指针的值, 赋给临时变量t
t := *a
// 取b指针的值, 赋给a指针指向的变量
*a = *b
// 将a指针的值赋给b指针指向的变量
*b = t
}
func main() {
// 准备两个变量, 赋值1和2
siteName, webSite := "秋码记录", "https://qiucode.cn"
// 交换变量值
swap(&siteName, &webSite)
// 输出变量值
fmt.Println(siteName, webSite)
}

代码说明如下:
- 第 6 行,定义一个交换函数,参数为 a、b,类型都为
*string 指针类型。 - 第 8 行,取
指针 a的值,并把值赋给变量 t,t 此时是string类型。 - 第 10 行,取 b 的指针值,赋给
指针 a 指向的变量。注意,此时*a的意思不是取 a 指针的值,而是 a 指向的变量。 - 第 12 行,将
t的值赋给指针 b 指向的变量。 - 第 16 行,准备
siteName、webSite两个变量,分别赋值为秋码记录和https://qiucode.cn,类型为string。 - 第 18 行,取出
siteName和webSite的地址作为参数传给swap() 函数进行调用。 - 第 20 行,交换完毕时,输出
siteName和webSite的值。
*操作符作为右值时,意义是取指针的值,作为左值时,也就是放在赋值操作符的左边时,表示 a 指针指向的变量。其实归纳起来,*操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值,当操作在左值时,就是将值设置给指向的变量。
如果swap()操作的是指针值,那会发生什么情况呢?
package main
import "fmt"
func swap(a, b *string) {
b, a = a, b
fmt.Printf("swap 函数中, a内存地址=%p,b内存地址=%p. a=%s,b=%s \n", a, b, *a, *b)
}
func main() {
// 准备两个变量
siteName, webSite := "秋码记录", "https://qiucode.cn"
// 交换变量值
swap(&siteName, &webSite)
fmt.Printf("main 函数中,siteName内存地址=%p,webSite内存地址=%p \n", &siteName, &webSite)
// 输出变量值
fmt.Println(siteName, webSite)
}

从运行结果可以看出,变量siteName与变量webSite并没有交换值。上述的swap()函数交换了两个变量的地址,在swap()函数块里,a和b变量值确实被交换了,但和a、b关联的siteName、webSite两个变量并没有实际关联。
本文介绍了Go语言中指针的基本概念及其使用方法,包括指针的声明、获取指针指向的值以及通过指针修改值等内容。
1274

被折叠的 条评论
为什么被折叠?



