摘要:Go支持指针,允许在程序中通过引用传递值或者数据结构。
go语言中的指针和C语言中的指针类似,但比C语言中的指针更简单。
// Go语言取地址符号是&,放到变量前会返回对应变量的内存地址
var i1 int = 1
var j = i1
fmt.Println(&i1)
fmt.Println(&j)
// 定义指针变量 var var_name *var_type
s := "sss"
p := 2181
var ip *string = &s
var port *int = &p
fmt.Println(*ip)
fmt.Println(*port)
变量、指针和地址三者的关系是,每个变量都拥有地址,指针的值就是地址。
通过&
获取对应变量的内存地址。 通过*
获取指针的值,也就是指针取值。取地址操作符 &
和取值操作符 *
是一对互补操作符,&
取出地址,*
根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
- 对变量进行取地址操作使用&操作符,可以获得这个变量的指针变量。
- 指针变量的值是指针地址。
- 对指针变量进行取值操作使用*操作符,可以获得指针变量指向的原变量的值。
通过New()创建指针
Go语言还提供了另外一种方法来创建指针变量,格式如下: new(type) 这个type可以为int。
// create ptr by new()
func createPtr() {
str := new(string)
*str = "ssss"
fmt.Println("str is : ", str)
fmt.Println("*str is : ", *str)
// str is : 0xc000116050
// *str is : ssss
}
new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。
数组指针
const numlen = 4
// 数组指针
nums := []int{1, 2, 3, 4}
// 指针数组的长度必须等与数组长度
var ptr [numlen]*int
for i2 := range nums {
ptr[i2] = &nums[i2]
}
for i := 0; i < numlen; i++ {
fmt.Println(*ptr[i])
}
指针的指针
// 指针的指针
pp := 12
p1 := &pp
p2 := &p1
fmt.Println("pp: ", pp)
fmt.Println("p1: ", *p1)
fmt.Println("p2: ", **p2)
函数指针
谈到函数指针,就不得不提到值传递和引用传递了。函数的参数中,如果是值传递,在函数体内部得到的是参数的拷贝,对参数修改不会影响原始参数;如果是引用传递,在函数体内部的到的就是参数的内存地址,对参数的修改会影响原始参数本身。
// 值传递
func zeroval(ival int) {
ival = 0
}
// 引用传递
func zeroptr(iptr *int) {
*iptr = 0
}
zeroval 有一个 int 型参数,所以使用值传递。zeroval函数将从调用方得到一个ival形参的拷贝。
zeroptr 有一和上面不同的 *int 参数,意味着它用了一个 int指针。函数体内的 *iptr 引用这个指针,从它内存地址得到这个地址对应的当前值。对一个引用的指针赋值将会改变这个指针引用的真实地址的值。
通过函数指针可以优雅地实现两值交换。
// 函数指针参数
x := 100
y := 200
fmt.Println("x : ", x)
fmt.Println("y : ", y)
swap(&x, &y)
fmt.Println("x : ", x)
fmt.Println("y : ", y)
//---
func swap(x *int, y *int) {
// 优雅的写法
*x, *y = *y, *x
//tmp := *x
//*x = *y
//*y = tmp
}
优雅地实现swap就是通过指针交换两值,如果说交换指针会怎么样呢?
// swap ptr
func swap1(x, y *int) {
x, y = y, x
}
// main()
aa := 1
bb := 3
swap1(&aa, &bb)
fmt.Println("aa: ", aa, " bb: ", bb)
// 结果:
// aa: 1 bb: 3
结果表明,交换是不成功的。上面代码中的 swap1() 函数交换的是 aa 和 bb 的地址,在交换完毕后,aa 和 bb 的变量值确实被交换。但和 aa、bb 关联的两个变量并没有实际关联。这就像写有两座房子的卡片放在桌上一字摊开,交换两座房子的卡片后并不会对两座房子有任何影响。
空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代空值。
一个指针变量通常缩写为 ptr。
// nilPtr
func nilPtr() {
var ptr *int
fmt.Println("ptr val is : ", ptr)
}
// 输出:
// ptr val is : <nil>