編程學(xué)習(xí)網(wǎng) > 編程語(yǔ)言 > go > 2020 重學(xué) Go 系列:07. 詳解數(shù)據(jù)類(lèi)型:指針
2020
03-17

2020 重學(xué) Go 系列:07. 詳解數(shù)據(jù)類(lèi)型:指針

0. 什么是指針

當(dāng)我們定義一個(gè)變量 name

var name string = "Go編程時(shí)光" 

此時(shí),name 是變量名,它只是編程語(yǔ)言中方便程序員編寫(xiě)和理解代碼的一個(gè)標(biāo)簽。

當(dāng)我們?cè)L問(wèn)這個(gè)標(biāo)簽時(shí),機(jī)算機(jī)會(huì)返回給我們它指向的內(nèi)存地址里存儲(chǔ)的值:Go編程時(shí)光。

出于某些需要,我們會(huì)將這個(gè)內(nèi)存地址賦值給另一個(gè)變量名,通常叫做 ptr(pointer的簡(jiǎn)寫(xiě)),而這個(gè)變量,我們稱(chēng)之為指針變量。

換句話說(shuō),指針變量(一個(gè)標(biāo)簽)的值是指針,也就是內(nèi)存地址。

根據(jù)變量指向的值,是否是內(nèi)存地址,我把變量分為兩種:

  • 普通變量:存數(shù)據(jù)值本身
  • 指針變量:存值的內(nèi)存地址

1. 指針的創(chuàng)建

指針創(chuàng)建有三種方法

第一種方法

先定義對(duì)應(yīng)的變量,再通過(guò)變量取得內(nèi)存地址,創(chuàng)建指針

// 定義普通變量 aint := 1 // 定義指針變量 ptr := &aint     

第二種方法

先創(chuàng)建指針,分配好內(nèi)存后,再給指針指向的內(nèi)存地址寫(xiě)入對(duì)應(yīng)的值。

// 創(chuàng)建指針 astr := new(string) // 給指針賦值 *astr = "Go編程時(shí)光" 

第三種方法

先聲明一個(gè)指針變量,再?gòu)钠渌兞咳〉脙?nèi)存地址賦值給它

aint := 1 var bint *int  // 聲明一個(gè)指針 bint = &aint   // 初始化 

上面的三段代碼中,指針的操作都離不開(kāi)這兩個(gè)符號(hào):

  • & :從一個(gè)普通變量中取得內(nèi)存地址
  • * :當(dāng) * 在賦值操作值的右邊,是從一個(gè)指針變量中取得變量值,當(dāng)*在賦值操作值的左邊,是指該指針指向的變量

通過(guò)下面這段代碼,你可以熟悉這兩個(gè)符號(hào)的用法

package main import "fmt" func main() {
    aint := 1     // 定義普通變量     ptr := &aint  // 定義指針變量     fmt.Println("普通變量存儲(chǔ)的是:", aint)
    fmt.Println("普通變量存儲(chǔ)的是:", *ptr)
    fmt.Println("指針變量存儲(chǔ)的是:", &aint)
    fmt.Println("指針變量存儲(chǔ)的是:", ptr)
}

輸出如下

普通變量存儲(chǔ)的是:1
普通變量存儲(chǔ)的是:1
指針變量存儲(chǔ)的是: 0xc0000100a0
指針變量存儲(chǔ)的是: 0xc0000100a0

要想打印指針指向的內(nèi)存地址,方法有兩種

// 第一種 fmt.Printf("%p", ptr) // 第二種 fmt.Println(ptr)

2. 指針的類(lèi)型

我們知道字符串的類(lèi)型是 string,整型是int,那么指針如何表示呢?

寫(xiě)段代碼試驗(yàn)一下就知道了

package main import "fmt" func main() {
    astr := "hello"     aint := 1     abool := false     arune := 'a'     afloat := 1.2     fmt.Printf("astr 指針類(lèi)型是:%T\n", &astr)
    fmt.Printf("aint 指針類(lèi)型是:%T\n", &aint)
    fmt.Printf("abool 指針類(lèi)型是:%T\n", &abool)
    fmt.Printf("arune 指針類(lèi)型是:%T\n", &arune)
    fmt.Printf("afloat 指針類(lèi)型是:%T\n", &afloat)
}

輸出如下,可以發(fā)現(xiàn)用 *+所指向變量值的數(shù)據(jù)類(lèi)型,就是對(duì)應(yīng)的指針類(lèi)型。

astr 指針類(lèi)型是:*string aint 指針類(lèi)型是:*int abool 指針類(lèi)型是:*bool arune 指針類(lèi)型是:*int32 afloat 指針類(lèi)型是:*float64 

所以若我們定義一個(gè)只接收指針類(lèi)型的參數(shù)的函數(shù),可以這么寫(xiě)

func mytest(ptr *int)  {
    fmt.Println(*ptr)
}

3. 指針的零值

當(dāng)指針聲明后,沒(méi)有進(jìn)行初始化,其零值是 nil。

func main() {  
    a := 25     var b *int  // 聲明一個(gè)指針     if b == nil {
        fmt.Println(b)
        b = &a  // 初始化:將a的內(nèi)存地址給b         fmt.Println(b)
    }
}

輸出如下

<nil> 0xc0000100a0 

4. 指針與切片

切片與指針一樣,都是引用類(lèi)型。

如果我們想通過(guò)一個(gè)函數(shù)改變一個(gè)數(shù)組的值,有兩種方法

  1. 將這個(gè)數(shù)組的切片做為參數(shù)傳給函數(shù)

  2. 將這個(gè)數(shù)組的指針做為參數(shù)傳給函數(shù)

盡管二者都可以實(shí)現(xiàn)我們的目的,但是按照 Go 語(yǔ)言的使用習(xí)慣,建議使用第一種方法,因?yàn)榈谝环N方法,寫(xiě)出來(lái)的代碼會(huì)更加簡(jiǎn)潔,易讀。具體你可以參數(shù)下面兩種方法的代碼實(shí)現(xiàn)

使用切片

func modify(sls []int) {  
    sls[0] = 90 } func main() {  
    a := [3]int{899091}
    modify(a[:])
    fmt.Println(a)
}

使用指針

func modify(arr *[3]int) {  
    (*arr)[0] = 90 } func main() {  
    a := [3]int{899091}
    modify(&a)
    fmt.Println(a)
}

掃碼二維碼 獲取免費(fèi)視頻學(xué)習(xí)資料

Python編程學(xué)習(xí)

查 看2022高級(jí)編程視頻教程免費(fèi)獲取