7. Go 語言數據類型:指針

Hi,你們好。git

我是明哥,在本身學習 Golang 的這段時間裏,我寫了詳細的學習筆記放在個人我的微信公衆號 《Go編程時光》,對於 Go 語言,我也算是個初學者,所以寫的東西應該會比較適合剛接觸的同窗,若是你也是剛學習 Go 語言,不防關注一下,一塊兒學習,一塊兒成長。程序員

個人在線博客:golang.iswbm.com 個人 Github:github.com/iswbm/GolangCodingTimegithub


0. 什麼是指針

當咱們定義一個變量 namegolang

var name string = "Go編程時光"複製代碼

此時,name 是變量名,它只是編程語言中方便程序員編寫和理解代碼的一個標籤。編程

當咱們訪問這個標籤時,機算機會返回給咱們它指向的內存地址裏存儲的值:Go編程時光數組

出於某些須要,咱們會將這個內存地址賦值給另外一個變量名,一般叫作 ptr(pointer的簡寫),而這個變量,咱們稱之爲指針變量。微信

換句話說,指針變量(一個標籤)的值是指針,也就是內存地址。編程語言

根據變量指向的值,是不是內存地址,我把變量分爲兩種:函數

  • 普通變量:存數據值自己
  • 指針變量:存值的內存地址

1. 指針的建立

指針建立有三種方法學習

第一種方法

先定義對應的變量,再經過變量取得內存地址,建立指針

// 定義普通變量
aint := 1
// 定義指針變量
ptr := &aint     複製代碼

第二種方法

先建立指針,分配好內存後,再給指針指向的內存地址寫入對應的值。

// 建立指針
astr := new(string)
// 給指針賦值
*astr = "Go編程時光"複製代碼

第三種方法

先聲明一個指針變量,再從其餘變量取得內存地址賦值給它

aint := 1
var bint *int  // 聲明一個指針
bint = &aint   // 初始化複製代碼

上面的三段代碼中,指針的操做都離不開這兩個符號:

  • & :從一個普通變量中取得內存地址
  • *:當*在賦值操做值的右邊,是從一個指針變量中取得變量值,當*在賦值操做值的左邊,是指該指針指向的變量

經過下面這段代碼,你能夠熟悉這兩個符號的用法

package main

import "fmt"

func main() {
    aint := 1     // 定義普通變量
    ptr := &aint  // 定義指針變量
    fmt.Println("普通變量存儲的是:", aint)
    fmt.Println("普通變量存儲的是:", *ptr)
    fmt.Println("指針變量存儲的是:", &aint)
    fmt.Println("指針變量存儲的是:", ptr)
}複製代碼

輸出以下

普通變量存儲的是: 1
普通變量存儲的是: 1
指針變量存儲的是: 0xc0000100a0
指針變量存儲的是: 0xc0000100a0複製代碼

要想打印指針指向的內存地址,方法有兩種

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

// 第二種
fmt.Println(ptr)複製代碼

2. 指針的類型

咱們知道字符串的類型是 string,整型是int,那麼指針如何表示呢?

寫段代碼試驗一下就知道了

package main

import "fmt"

func main() {
    astr := "hello"
    aint := 1
    abool := false
    arune := 'a'
    afloat := 1.2

    fmt.Printf("astr 指針類型是:%T\n", &astr)
    fmt.Printf("aint 指針類型是:%T\n", &aint)
    fmt.Printf("abool 指針類型是:%T\n", &abool)
    fmt.Printf("arune 指針類型是:%T\n", &arune)
    fmt.Printf("afloat 指針類型是:%T\n", &afloat)
}複製代碼

輸出以下,能夠發現用 *+所指向變量值的數據類型,就是對應的指針類型。

astr 指針類型是:*string
aint 指針類型是:*int
abool 指針類型是:*bool
arune 指針類型是:*int32
afloat 指針類型是:*float64複製代碼

因此若咱們定義一個只接收指針類型的參數的函數,能夠這麼寫

func mytest(ptr *int)  {
    fmt.Println(*ptr)
}複製代碼

3. 指針的零值

當指針聲明後,沒有進行初始化,其零值是 nil。

func main() {  
    a := 25
    var b *int  // 聲明一個指針

    if b == nil {
        fmt.Println(b)
        b = &a  // 初始化:將a的內存地址給b
        fmt.Println(b)
    }
}複製代碼

輸出以下

<nil>
0xc0000100a0複製代碼

4. 指針與切片

切片與指針同樣,都是引用類型。

若是咱們想經過一個函數改變一個數組的值,有兩種方法

  1. 將這個數組的切片作爲參數傳給函數
  2. 將這個數組的指針作爲參數傳給函數

儘管兩者均可以實現咱們的目的,可是按照 Go 語言的使用習慣,建議使用第一種方法,由於第一種方法,寫出來的代碼會更加簡潔,易讀。具體你能夠參數下面兩種方法的代碼實現

使用切片

func modify(sls []int) {  
    sls[0] = 90
}

func main() {  
    a := [3]int{89, 90, 91}
    modify(a[:])
    fmt.Println(a)
}複製代碼

使用指針

func modify(arr *[3]int) {  
    (*arr)[0] = 90
}

func main() {  
    a := [3]int{89, 90, 91}
    modify(&a)
    fmt.Println(a)
}複製代碼

系列導讀

01. 開發環境的搭建(Goland & VS Code)

02. 學習五種變量建立的方法

03. 詳解數據類型:**整形與浮點型**

04. 詳解數據類型:byte、rune與string

05. 詳解數據類型:數組與切片

06. 詳解數據類型:字典與布爾類型

07. 詳解數據類型:指針

08. 面向對象編程:結構體與繼承

09. 一篇文章理解 Go 裏的函數

10. Go語言流程控制:if-else 條件語句

11. Go語言流程控制:switch-case 選擇語句

12. Go語言流程控制:for 循環語句

13. Go語言流程控制:goto 無條件跳轉

14. Go語言流程控制:defer 延遲調用

15. 面向對象編程:接口與多態

16. 關鍵字:make 和 new 的區別?

17. 一篇文章理解 Go 裏的語句塊與做用域

18. 學習 Go 協程:goroutine

19. 學習 Go 協程:詳解信道/通道

20. 幾個信道死鎖經典錯誤案例詳解

21. 學習 Go 協程:WaitGroup

22. 學習 Go 協程:互斥鎖和讀寫鎖

23. Go 裏的異常處理:panic 和 recover

24. 超詳細解讀 Go Modules 前世此生及入門使用

25. Go 語言中關於包導入必學的 8 個知識點

26. 如何開源本身寫的模塊給別人用?

27. 說說 Go 語言中的類型斷言?

28. 這五點帶你理解Go語言的select用法


相關文章
相關標籤/搜索