Go语言指针

2021/06/05

Tags: Go

摘要: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>