Go語言 值矢门,指針,引用類型


Go語言的指針與C或C++的指針類似灰蛙,但是Go語言的指針不支持指針運(yùn)算祟剔,這樣就消除了在C或C++程序中一些潛在的問題。由于Go語言有自己的垃圾回收器缕允,并且會(huì)自動(dòng)管理內(nèi)存峡扩,所以Go語言也不需要像C或C++一樣使用free函數(shù)或者delete操作符。

Go語言的指針創(chuàng)建后可以像Java和Python中對象的引用一樣使用障本。

在Go語言中教届,對于布爾變量或數(shù)值類型或字符串類型或數(shù)組都是按照值傳遞的:值在傳遞給函數(shù)或者方法時(shí)會(huì)被復(fù)制一份,然后方法或函數(shù)使用的是復(fù)制的這份值驾霜,也就不會(huì)對原值產(chǎn)生什么影響案训。一般情況下,對于布爾變量或數(shù)值類型或字符串類型的按值傳遞是非常廉價(jià)的粪糙,Go語言編譯器會(huì)在傳遞過程中進(jìn)行安全優(yōu)化强霎。

但是在Go語言中,字符串是不可變的蓉冈,因此在進(jìn)行修改字符串時(shí)(例如使用+=操作)城舞,Go語言必須創(chuàng)建一個(gè)新的字符串,然后復(fù)制原始的字符串并將其添加到新字符串之后寞酿,對于大字符串來說家夺,操作的代價(jià)可能會(huì)比較大。

對于大字符串是這樣伐弹,對于數(shù)組進(jìn)行值傳遞也是如此拉馋。為了解決可能產(chǎn)生的巨大代價(jià),Go語言使用數(shù)組切片來代替數(shù)組的使用。傳遞一個(gè)切片的代價(jià)跟傳遞字符串差不多煌茴,無論該切片的長度或容量是多大随闺。對切片進(jìn)行復(fù)制修改操作也不會(huì)像字符串那樣需要?jiǎng)?chuàng)建新的切片,因?yàn)榍衅强勺兊穆瑢儆谝妙愋汀?/p>

func main() {
   a := 3
   b := 4
   c := "abc"
   d := [3]int{1,2,3}
   fmt.Printf("main方法:a的值為 %v,b的值為 %v,c的值為 %v,d的值為 %v \n",a,b,c,d)
   demo(a,b,c,d)
   fmt.Printf("main方法:a的值為 %v,b的值為 %v,c的值為 %v,d的值為 %v \n",a,b,c,d)
}

func demo(a,b int,c string,d [3]int) {
   a = 5
   b = 6
   c = "efg"
   d[0] = 0
   fmt.Printf("demo函數(shù):a的值為 %v,b的值為 %v,c的值為 %v,d的值為 %v\n",a,b,c,d)
}
----output----
main方法:  a的值為 3,b的值為 4,c的值為 abc,d的值為 [1 2 3]
demo函數(shù): a的值為 5,b的值為 6,c的值為 efg,d的值為 [0 2 3]
main方法:  a的值為 3,b的值為 4,c的值為 abc,d的值為 [1 2 3]

Go語言中的引用類型有:映射(map)矩乐,數(shù)組切片(slice),通道(channel)合住,方法與函數(shù)绰精。

由于Go語言存在垃圾回收器,因此在一個(gè)本地變量不再被使用時(shí)(不再被引用或者不在作用于范圍)就會(huì)被垃圾回收器回收掉透葛,這時(shí)本地變量的生命周期由它們的作用域決定。那如果我們想要管理本地變量的生命周期呢卿樱?這時(shí)就需要使用指針來管理本地變量僚害,只要該變量至少存在一個(gè)指針,那么該變量的生命周期就可以獨(dú)立于作用域繁调。

使用指針能讓我們控制變量的生命周期萨蚕,不受作用域的影響,另外變量在傳遞過程中成本最小化蹄胰,且可以輕易的修改變量的內(nèi)容岳遥,而不是對復(fù)制的值進(jìn)行操作。指針是一個(gè)變量裕寨,這個(gè)變量實(shí)際上是保存了另一個(gè)變量的內(nèi)存地址浩蓉,任何被指針保存了內(nèi)存地址的變量都可以通過指針來修改內(nèi)容。指針的傳遞非常廉價(jià)宾袜。

在使用指針前捻艳,我們需要明白兩個(gè)操作符的含義
①操作符& : 當(dāng)作二元操作符時(shí),是按位與操作庆猫;當(dāng)作一元操作符時(shí)认轨,是返回該變量的內(nèi)存地址。
②操作符* : 當(dāng)作二元操作符時(shí)月培,是相乘的操作嘁字;當(dāng)作一元操作符(解引用操作符)時(shí),是返回該指針指向的變量的值杉畜,其實(shí)就是解除變量的指針引用纪蜒,返回該變量的值。

指針的創(chuàng)建與使用寻行,可以看下面的代碼實(shí)例

func main() {
   a := 3
   p := &a //這里是獲取變量a的內(nèi)存地址霍掺,并將其賦值給變量p
   fmt.Printf("a的值為 %v, a的指針是 %v ,p指向的變量的值為 %v\n",a,p,*p)
}
-----output-----
a的值為 3, a的指針是 0xc042060080 ,p指向的變量的值為 3

其實(shí)*p和變量a的值是相等的杆烁,兩者可以交換著使用牙丽,兩者都與同一塊內(nèi)存地址相關(guān)聯(lián),任意一個(gè)變量進(jìn)行修改操作都會(huì)影響到另一個(gè)變量的值兔魂,但是若變量p被賦值其他變量的指針就不行了烤芦。

關(guān)于指針的綜合運(yùn)用,我們看以下的代碼實(shí)例

func main() {
   a := 3
   b := 4
   p1 := &a //獲取變量a的內(nèi)存地址析校,并將其賦值給變量p1
   p2 := &b //獲取變量b的內(nèi)存地址构罗,并將其賦值給變量p2
   fmt.Printf("a的值為 %v, a的指針是 %v ,p1指向的變量的值為 %v\n",a,p1,*p1)
   fmt.Printf("b的值為 %v, b的指針是 %v 智玻,p2指向的變量的值為 %v\n",b,p2,*p2)
   fmt.Println(demo(p1,p2))
   fmt.Printf("a的值為 %v, a的指針是 %v 遂唧,p1指向的變量的值為 %v\n",a,p1,*p1)
   fmt.Printf("b的值為 %v, b的指針是 %v ,p2指向的變量的值為 %v\n",b,p2,*p2)
}

func demo(a,b *int)int  {
   *a = 5
   *b = 6
   return  *a * *b //這里出現(xiàn)連續(xù)的兩個(gè)*吊奢,Go編譯器會(huì)根據(jù)上下文自動(dòng)識別乘法與兩個(gè)引用
}
-----output-----
a的值為 3, a的指針是 0xc042060080 盖彭,p1指向的變量的值為 3
b的值為 4, b的指針是 0xc042060088 ,p2指向的變量的值為 4
30
a的值為 5, a的指針是 0xc042060080 页滚,p1指向的變量的值為 5
b的值為 6, b的指針是 0xc042060088 召边,p2指向的變量的值為 6

根據(jù)上面代碼,我們可以看到使用指針后裹驰,本來是值傳遞的整數(shù)類型在函數(shù)或方法中修改會(huì)影響到原變量的值隧熙。

空指針
當(dāng)一個(gè)指針被定義后沒有分配到任何變量時(shí),它的值為 nil幻林。
nil 指針也稱為空指針贞盯。
nil在概念上和其它語言的null、None滋将、nil邻悬、NULL一樣,都指代零值或空值随闽。
查看以下實(shí)例:

package main

import "fmt"
func main() {
   var  ptr *int
   fmt.Printf("ptr 的值為 : %x\n", ptr  )
}

以上實(shí)例輸出結(jié)果為:

ptr 的值為 : 0

空指針判斷:

if(ptr != nil)     /* ptr 不是空指針 */
if(ptr == nil)    /* ptr 是空指針 */

多重間接引用
以上面代碼為例父丰, 在a := 3, p1 := &a中掘宪,p1是指向a的內(nèi)存地址蛾扇,這種叫做間接引用,若還有一個(gè)p2是指向p1的內(nèi)存地址魏滚,p1指向a的內(nèi)存地址镀首,這種就叫做多重間接引用,不管哪種引用鼠次,若其中一個(gè)變量進(jìn)行修改內(nèi)容操作更哄,均會(huì)影響到其他所有變量的內(nèi)容芋齿。

func main() {
   a := 3
   p1 := &a  //p1是指向變量a內(nèi)存地址的指針
   p2 := &p1 //p2是指向變量p1內(nèi)存地址的指針
   fmt.Printf("a:%v, p1:%v, *p1:%v, p2:%v, **p2:%v\n",a,p1,*p1,p2,**p2)
   a = 4
   fmt.Printf("a:%v, p1:%v, *p1:%v, p2:%v, **p2:%v\n",a,p1,*p1,p2,**p2)
}
-----output-----
a:3, p1:0xc0420080b8, *p1:3, p2:0xc042004028, **p2:3
a:4, p1:0xc0420080b8, *p1:4, p2:0xc042004028, **p2:4

new函數(shù)與&操作符
Go語言中提供兩種創(chuàng)建變量的方式,同時(shí)可以獲得指向它們的指針:new函數(shù)與&操作符成翩。這兩種的使用方式如下面代碼所示

type Person struct {
   name string
   sex  string
   age int
}
func main() {
   person1 := Person{"zhangsan","man",25} //創(chuàng)建一個(gè)person1對象
   person2 := new(Person)//使用new創(chuàng)建一個(gè)person2對象觅捆,同時(shí)獲得person的指針
   person2.name,person2.sex,person2.age = "wangwu","man",25
   person3 := &Person{"lisi","man",25}//使用&創(chuàng)建一個(gè)person3對象,同時(shí)獲得person的指針
   fmt.Printf("person1:%v, person2:%v, person3:%v\n",person1,person2,person3)
}
-----output-----
person1:{zhangsan man 25}, person2:&{wangwu man 25}, person3:&{lisi man 25}

從輸出結(jié)果來看麻敌,new函數(shù)與&操作符兩種方式區(qū)別不大栅炒,&操作符創(chuàng)建起來更加的簡潔,并且隨時(shí)可以指定屬性初始值术羔。Go語言打印指向person的指針時(shí)赢赊,會(huì)打印person屬性的具體內(nèi)容,并且在前綴上加上&表示該變量是一個(gè)指針级历。

接下來我們來傳遞一個(gè)結(jié)構(gòu)體指針释移,并修改結(jié)構(gòu)體的屬性,看看Go語言是如何操作的寥殖。

type Person struct {
   name string
   sex  string
   age int
}
func main() {
   person1 := Person{"zhangsan","man",25} //創(chuàng)建一個(gè)person1對象
   fmt.Printf("person1:%v\n",person1)
   demo(&person1)
   fmt.Printf("person1:%v\n",person1)
}

func demo(person *Person)  {
   (*person).age = 18 //顯示的解引用
   person.name = "GoLang" //隱式的解引用
}

main函數(shù)中創(chuàng)建一個(gè)pserson1對象秀鞭,設(shè)置初始化屬性后將它的指針傳遞到demo函數(shù)中,大家可以看到demo函數(shù)中有兩種解引用(就是將一個(gè)指針轉(zhuǎn)化為原對象)的方式扛禽,第一種: (*person).age是顯示的解引用,第二種是使用 "." 操作符自動(dòng)的將指針解引用皱坛,使用上這兩種沒什么區(qū)別编曼,但第二種更簡單。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剩辟,一起剝皮案震驚了整個(gè)濱河市掐场,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贩猎,老刑警劉巖熊户,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吭服,居然都是意外死亡嚷堡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門艇棕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝌戒,“玉大人,你說我怎么就攤上這事沼琉”惫叮” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵打瘪,是天一觀的道長友鼻。 經(jīng)常有香客問我傻昙,道長,這世上最難降的妖魔是什么彩扔? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任妆档,我火速辦了婚禮,結(jié)果婚禮上借杰,老公的妹妹穿的比我還像新娘过吻。我一直安慰自己,他們只是感情好蔗衡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布纤虽。 她就那樣靜靜地躺著,像睡著了一般绞惦。 火紅的嫁衣襯著肌膚如雪逼纸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天济蝉,我揣著相機(jī)與錄音杰刽,去河邊找鬼。 笑死王滤,一個(gè)胖子當(dāng)著我的面吹牛贺嫂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雁乡,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼第喳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了踱稍?” 一聲冷哼從身側(cè)響起曲饱,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎珠月,沒想到半個(gè)月后扩淀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啤挎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年驻谆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侵浸。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旺韭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掏觉,到底是詐尸還是另有隱情区端,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布澳腹,位于F島的核電站织盼,受9級特大地震影響杨何,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沥邻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一危虱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唐全,春花似錦埃跷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至延届,卻和暖如春剪勿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背方庭。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工厕吉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人械念。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓头朱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親龄减。 傳聞我的和親對象是個(gè)殘疾皇子髓窜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • ??引用類型的值(對象)是引用類型的一個(gè)實(shí)例。 ??在 ECMAscript 中鳖敷,引用類型是一種數(shù)據(jù)結(jié)構(gòu)脖苏,用于將數(shù)...
    霜天曉閱讀 1,054評論 0 1
  • 我還不知道這篇文章意味著什么棍潘。我只是萬千星輝中的一點(diǎn),星辰大海要三分了嗎崖媚? 我看不到原來的你們亦歉,也許我喜歡的,只是...
    一見鐘情一世相守閱讀 344評論 0 0