定義
指針,就是保存對(duì)象的內(nèi)存地址。用指針的好處就是節(jié)約內(nèi)存空間。
定義一個(gè)指針類型的變量很簡單,就是在變量名前加*
//基礎(chǔ)類型指針
var ps *string
var pi *int
var pf *float64
var pb *bool
//結(jié)構(gòu)體指針
type Person struct {
name string
age int
}
var pperson *Person
使用
在把指針使用的得心應(yīng)手之前,首先要熟悉go語言中這兩個(gè)操作符:*與&。
先說說&。&變量名,表示對(duì)變量取地址。&可以理解為一個(gè)方法簡寫,這個(gè)方法的唯一參數(shù)是變量名,返回值是一個(gè)內(nèi)存地址(即一個(gè)指針類型變量)。&的使用如下:
//先定義指針
var ps *string
//再定義變量
var s string
s = "i am string"
//通過&操作符取s的內(nèi)存地址,地址保存到指針ps中
ps = &s
fmt.Printf("value of s:%s\n",s)
fmt.Printf("value of ps:%v\n",ps)
以上代碼的執(zhí)行結(jié)果:
value of s:i am string
value of ps:0xc42007a1c0
需要注意的一點(diǎn)就是指針與變量必須是同類型的。你不能把一個(gè)int類型的變量地址賦給一個(gè)string類型的指針。
再來說說*。*在指針的使用中有兩個(gè)角色:
其一,作為指針類型的定義符,本文開篇就用到了
其二,與&符做相反操作,&變量名是對(duì)變量取地址,而*指針名則是對(duì)指針地址取其保存的內(nèi)容。同樣可以理解*是一個(gè)方法的簡寫,此方法唯一參數(shù)是一個(gè)指針類型變量(也就是一個(gè)內(nèi)存地址),返回值是這個(gè)地址保存的變量真實(shí)值。接上段代碼:
fmt.Printf("ps point to:%s\n",*ps)
輸出:
ps point to:i am string
從這三行輸出上可以很明確的看出兩個(gè)操作符的作用了。需要注意的一點(diǎn)就是有兩個(gè)用途,在看別人的代碼時(shí),把這兩種場景區(qū)分開,明確了解每個(gè)起的什么作用,就不會(huì)迷失于*&之海了。
上面只是演示指針怎么用,而實(shí)際項(xiàng)目當(dāng)中最常用的場景就是用指針作方法返回值和參數(shù)了。不難理解,在函數(shù)傳參和返回值的時(shí)候,用指針類型代替值類型,通過引用取值(指針就是對(duì)值的引用),復(fù)用已創(chuàng)建對(duì)象,減少內(nèi)存開銷,當(dāng)然就達(dá)到了節(jié)約內(nèi)存,提高程序效率的目的。實(shí)際傳遞的數(shù)據(jù)類型往往是結(jié)構(gòu)體:
//結(jié)構(gòu)體指針
type Person struct {
Name string
Age int
}
var pperson *Person
var person Person
person = Person{
"luna",
20,
}
pperson = &person
然后定義一個(gè)方法,對(duì)于傳入的Person對(duì)象,年齡增加1并返回,參數(shù)和返回值都是用指針:
func yearGone(p *Person) *Person {
p.Age += 1
return p
}
func main() {
person = Person{
"luna",
20,
}
fmt.Printf("last year:%v\n", person)
p := yearGone(&person)
fmt.Printf("now:%v\n", *p)
fmt.Printf("person now:%v\n", person)
}
輸出:
last year:{luna 20}
now:{luna 21}
person now:{luna 21}
這里從頭到尾,就只創(chuàng)建一個(gè)Person對(duì)象person,所有操作都是對(duì)它自己。注意打印p的內(nèi)容時(shí)用了*p,因?yàn)閜是指針類型變量,直接打印p只是個(gè)地址而已。
當(dāng)你看別人的代碼困惑與為什么這里用了指針而那里沒用時(shí),我的建議是永遠(yuǎn)不要問別人為什么用了(沒用)指針-_-。有時(shí)這個(gè)原因只是“看心情而已”。