0. 什么是指針
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ù)組的值,有兩種方法
-
將這個(gè)數(shù)組的切片做為參數(shù)傳給函數(shù)
-
將這個(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{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) }
掃碼二維碼 獲取免費(fèi)視頻學(xué)習(xí)資料
- 本文固定鏈接: http://phpxs.com/post/7150/
- 轉(zhuǎn)載請(qǐng)注明:轉(zhuǎn)載必須在正文中標(biāo)注并保留原文鏈接
- 掃碼: 掃上方二維碼獲取免費(fèi)視頻資料