指针
指针概念在Go语言中被拆分为两个核心概念:
- 类型指针,允许对这个指针类型的数据进行修改。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。
- 切片,由指向起始元素的原始指针、元素数量和容量组成。
认识指针地址和指针类型
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用“&”操作符放在变量前面对变量进行“取地址”操作。
ptr := &v // v的类型为T
其中v代表被取地址的变量,被取地址的v使用ptr变量进行接收,ptr的类型就为“*T”,称做T的指针类型。*
代表指针。
- 创建D:\go\src\指针\main.go
package main
import "fmt"
func main() {
var cat int = 1
var str string = "banana"
fmt.Printf("%p %p", &cat, &str)
}
// 下方为执行结果
----------------------------------------------------
PS D:\go\src\指针> go run main.go
0xc0000aa058 0xc000088220
-----------------------------------------------------
使用fmt.Printf的动词“%p”输出cat和str变量取地址后的指针值,指针值带有“0x”的十六进制前缀。
输出值在每次运行是不同的,代表cat和str两个变量在运行时的地址。在32位平台上,将是32位地址;64位平台上是64位地址。
提示:变量、指针和地址三者的关系是:每个变量都拥有地址,==指针的值就是地址==。
从指针获取指针指向的值
在对普通变量使用“&”操作符取地址获得这个变量的指针后,可以对指针使用*
操作,也就是指针取值。
查看地址的类型。对地址取值。
package main
import "fmt"
func main() {
var cat int = 1
var str string = "banana"
catPtr := &cat
strPtr := &str
fmt.Printf("catPtr type:%T\nstrPtr type:%T\n", catPtr, strPtr)
fmt.Println(catPtr, strPtr)
fmt.Println(*catPtr, *strPtr)
}
----------------------------------------------------
PS D:\go\src\指针> go run main.go
catPtr type:*int
strPtr type:*string
0xc0000120a8 0xc00005a230
1 banana
----------------------------------------------------
取地址操作符&
和取值操作符*
是一对互补操作符,&
取出地址,*
根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
- 对变量进行取地址(&)操作,可以获得这个变量的指针变量。
- 指针变量的值是指针地址。
- 对指针变量进行取值
*
操作,可以获得指针变量指向的原变量的值。
使用指针修改值
通过指针不仅可以取值,也可以修改值。前面已经使用多重赋值的方法进行数值交换,使用指针同样可以进行数值交。
package main
import "fmt"
func swap(x, y *int) {
// 取y指针的值赋值给x地址的变量,取x指针的值赋值给y地址的变量
*x, *y = *y, *x
}
func main() {
a := 1
b := 2
swap(&a, &b)
fmt.Println(a, b)
}
----------------------------------------------------
PS D:\go\src\指针> go run main.go
2 1
----------------------------------------------------
*x, *y = *y, *x
左侧的*x,*y
表示x,y指向的变量。
右侧的*y,*x
表示指针取到的值(整数类型)。
package main
import "fmt"
func swap(x, y *int) {
x, y = y, x
}
func main() {
a := 1
b := 2
swap(&a, &b)
fmt.Println(a, b)
}
----------------------------------------------------
PS D:\go\src\指针> go run main.go
1 2
----------------------------------------------------
结果表明,交换是不成功的。上面代码中的swap()函数交换的是x和y的地址,在交换完毕后,x和y的变量值确实被交换。但和x、y关联的两个变量a、b并没有实际关联。这就像写有两座房子地址的卡片放在桌上,交换两张卡片后并不会对两座房子有任何影响。
创建指针的另一种方法——new()函数
package main
import "fmt"
func main() {
str := new(string)
*str = "hello world!"
fmt.Println(*str, str)
}
----------------------------------------------------
PS D:\go\src\指针> go run main.go
hello world! 0xc000088220
----------------------------------------------------
new()函数可以创建一个对应类型的指针,创建过程会分配内存。被创建的指针指向的值为默认值。