go 基礎之指針

要搞明白 Go 語言中的指針需要先知道 3 個概念:指針地址、指針類型和指針取值。

go-func-pointer

Go 語言中的指針

Go 語言中的函數傳參都是值拷貝,當我們想要修改某個變量的時候,我們可以創建一個指向該變量地址的指針變量。傳遞數據使用指針,而無須拷貝數據。類型指針不能進行偏移和運算。Go 語言中的指針操作非常簡單,只需要記住兩個符號:&(取地址)和*(根據地址取值)。

比如下面的代碼:

var a = 3
fmt.Printf("num is : %d, it's location in memory: %p\n", a, &a)
輸出:

num is : 3, it's location in memory: 0xc000062080

可以看到 & a 輸出了 a 的內存地址。

你可以將 & a 賦值給一個變量, 然後觀察這個變量的類型,使用reflect.TypeOf()方法:

var a = 3
b := &a
fmt.Println(reflect.TypeOf(b))

輸出:
*int

可以看到 & a 的返回類型是 *int。

我們可以將一個變量的內存地址放在一個叫做指針的特殊數據類型中,聲明一個指針的方式如下:

var p *int

然後我們可以使用 p 去指向一個內存地址:

p = &a

那麼我們如何通過指針來獲取對應內存地址的值呢,這也是有辦法的。你可以在指針類型前面加上 * 號(前綴)來獲取指針所指向的內容,這裏的 * 號是一個類型更改器。使用一個指針引用一個值被稱爲間接引用。

func main() {
    //指針取值
    a := 10
    b := &a // 取變量a的地址,將指針保存到b中
    fmt.Printf("type of b:%T\n", b)
    c := *b // 指針取值(根據指針去內存取值)
    fmt.Printf("type of c:%T\n", c)
    fmt.Printf("value of c:%v\n", c)
}

輸出如下:

type of b:*int
type of c:int
value of c:10

當一個指針被定義沒有分配任何變量的時候,它的值爲 nil。

指針傳值示例

// 值傳遞x
func modify1(x int) {
    x = 100
}

// 指針類型x
func modify2(x *int) {
    *x = 100
}

func main() {
    a := 10
    modify1(a) // 此時的修改不會改變a的值,因爲傳遞的是a的一個副本
    fmt.Println(a) // 10
    modify2(&a) // 傳遞了a的指針地址,並且接收參數是指針類型,所以會被修改
    fmt.Println(a) // 100
}

對於任何一個變量 val,如下表達式都是正確的:

var == *(&var)

有如下你需要注意的是,你不能獲取到一個常量或者一個沒有賦值操作的文字的內存地址:

const PI  = 3.14
piP := &PI Cannot take the address of 'PI'
p2 := &3 Cannot take the address of '3'

空指針

package main

import"fmt"

func main() {
    var p *string
    fmt.Println(p)
    fmt.Printf("p的值是%v\n", p)
    if p != nil {
        fmt.Println("非空")
    } else {
        fmt.Println("空值")
    }
}

總結

references

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/GjoQySRwN64rMAmLH2RRzg