分水嶺 golang入坑系列

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

第三式開篇語有些負面, 所以這裡就不貼了。有興趣的自己可以去看看 https://andy-zhangtao.gitbooks.io/golang/content/ 。怒髮衝冠,意氣之作。看完就完了,別當真。把下面的東西當真就行。

不看內容,只看標題還以為這是一個小說呢。 如果哪天心血來潮,沒準會寫一篇小說。但自從參加朋友婚姻之後,就受到了打擊。 同樣進入30歲,有的同學已經年入上百萬,前呼後擁。 而自己除了會寫點"水貨"代碼,別無他長。 感慨良多,還是感覺自己不是一塊能依靠寫代碼發家致富的料。 所以會分出一部精力,來考慮如何?技術變現。 但這個系列仍然會寫完,不會虎頭蛇尾。因此本節起名:分水嶺。(這裡為cnblogs的乁卬楊同學發一封表揚信,這位同學大膽留言說第三式寫的有些負面,我重看了一下第三式,的確有些負面。 所以汲取教訓,寫好才是王道,我的文章我說了算!再次謝謝乁卬楊同學)

如果沒有C/C++語言經曆的同學,估計很少會使用過指標,這個名詞應該是在職業生涯當中經常會聽到,但很少會使用到的。 尤其什麼時候用*,什麼時候用&,只靠死記硬背很難活學活用。而在Golang當中,指標的使用變得有些簡單。像在前幾節講解函數參數之時,提到Golang參數預設是值傳遞,但有的時候通過指標可以達到引用傳遞的作用。而這也只是指標在Golang當中一個使用情境,本節將會具體聊聊Golang中如何使用指標。

正如前面所述,在Golang當中每個變數都是一個記憶體位置,每個記憶體位置都有它定義的地址,可以使用&運算子訪問它,它表示記憶體中的地址。例如下面的例子:

var a int = 10   fmt.Printf("%x\n", &a )

這樣通過&a,就輸出了a的記憶體位址。每次輸出的地址,有可能相同也有可能不相同。這取決於當時的記憶體使用量狀態。 如果記憶體資源不緊張,Golang的GC就不會回收這塊記憶體,輸出的就是同一塊地址。 如果記憶體緊張,GC就會回收垃圾記憶體,然後運行時重新分配一塊記憶體,那時就輸出一塊新地址。

在大學或者其他教程中,應該會提到過什麼是指標。 為了一俗到底,這裡再提一遍:指標是一個變數,儲存的是記憶體位址。與任何變數或常量一樣,必須先聲明一個指標(變數),然後才能使用它來儲存任何記憶體位址。通過下面文法可以聲明指標變數:

var name *type

type指的是資料類型,name則是指標名稱。*不能丟,表示這是一個指標類型的變數。如果沒有*,就變成一個普通資料變數了。比如聲明一個int類型,是這樣:

var i int

而聲明一個int類型的指標,則是:

var i *int

因為指標儲存的是記憶體位址,所以其長度都是相同的,是一個表示記憶體位址的長十六進位數字。不同資料類型指標之間的唯一區別是指標指向的記憶體所儲存的資料類型。舉個例子:每家家門鑰匙長得都一樣(是同一批防盜門),但每家裡面的戶型就千奇百怪了。 這裡面,鑰匙就是指標,而戶型就是資料類型。 我們可以說A鑰匙指的是二居室,而B鑰匙指的是四居室。

聲明完指標類型之後,就可以使用指標了。因此,下面來看如何使用指標。

使用指標三板斧:

  1. 聲明一個指標。
  2. 將真正資料的記憶體位址賦給這個指標
  3. 取出指標儲存的記憶體位址,然後通過這個地址取出資料。

指標的使用,基本就是這三板斧。而賦值,取值操作就依靠*和&來操作。對照著例子來看:

package mainimport "fmt"func main() {   var a int = 20      var ip *int         ip = &a     fmt.Printf("Address of a variable: %x\n", &a  )   fmt.Printf("Address stored in ip variable: %x\n", ip )   fmt.Printf("Value of *ip variable: %d\n", *ip )}
var a int = 20

聲明了一個int類型的普通變數,把20擱到裡面去。

然後第一斧(聲明指標) var ip *int。 聲明了一個指標,準備用來儲存int類型的變數。(記憶體位址長度都一樣,但Golang是強型別語言,所以必須告訴編譯器你準備儲存什麼類型的資料,因此聲明成*int)

然後砍上第二斧,將a的地址給了ip。通過&a取出a的記憶體位址,然後ip = &a就把地址給了ip。

最後三板斧,取出地址裡面的資料,也就是最後一個Printf裡面的*ip。 這裡面,繞了個彎。 如果直接用ip,那其實是將ip儲存的資料列印出來(想想如果i=1, 直接輸出i,是多少?)。這個地址本身沒有用,我們需要的是這個地址所對應的資料(好比小偷不關注鑰匙,關注的是鑰匙能開啟那扇門)。所以通過*ip,就直接取出ip所儲存地址裡面的資料了。

如果繞了,就把自個想象成小偷(意淫一下,別真去)。給你一個鑰匙,你不心動。而如果告訴你這把鑰匙能開那扇門,這個時候才最心動。所以ip儲存的是鑰匙,而*ip就是告訴你是那扇門。

既然說到鑰匙了,就接著往下說。 配鑰匙師傅那裡都掛著一串空白鑰匙,這個專業術語就是null 指標。null 指標也是一個指標變數類型,只不過沒有儲存任何地址。想想空白鑰匙,那扇門都打不開。

當剛開始第一板斧的時候(var ip *int),其實就已經是null 指標了。此時預設值就是0.在絕大多數的作業系統中,0都是一個很神奇的數字,介於天堂和地獄之間。 所以作業系統不讓使用者直接存取0地址(其實就是作業系統不放心使用者,擔心使用者瞎搗亂)。在Golang當中,特意為空白指標起了個名字,叫做nil。例如下面:

if(ptr != nil){ ... 不是null 指標 }     if(ptr == nil){ ... 是null 指標 }

如果你能熟練背出指標三板斧,那麼你就掌握50%了。 如果不能.... 重新GOTO line1,然後Loop。下面開始剩餘50%的指標大法。

指標在數組中的應用

莫緊張,不要看到指標就感覺是相親。 指標比妹子容易對付多了。妹子的世界是太極拳,虛虛實實,拳無定式。對付妹子,就跟聖鬥士一樣,同樣的招式不能用兩遍(是不是車田正美也受到了妹子的啟發)。而Golang大法,招招式式,都寫的很清楚。先來看普通數組如何使用:

   a := []int{10,100,200}   var i int   for i = 0; i < MAX; i++ {      fmt.Printf("Value of a[%d] = %d\n", i, a[i] )   }

初始化三個值,然後依次取出。 改造一下,把指標糅合進去。

   const MAX int = 3   a := []int{10,100,200}   var i int   var ptr [MAX]*int;   for  i = 0; i < MAX; i++ {      ptr[i] = &a[i] /* assign the address of integer. */   }   for  i = 0; i < MAX; i++ {      fmt.Printf("Value of a[%d] = %d\n", i,*ptr[i] )   }

指標的數組使用起來,就和其它數組的使用一模一樣。以前怎麼用,現在還怎麼用。唯一的變化就是,以前的數組儲存的是數,而現在的指標資料儲存的是地址。 除此之外,毫無區別。 兩個例子一對比就夠了,沒啥說的。

指標的指標

這種情境不得不說。 你可以不去使用,但萬一看到了,不能不知道。說實話,使用這個大招的,十有八九是從C++轉過來的。不能說不好,個人習慣吧。 我是不喜歡用,畢竟要考慮代碼的可讀性。(學乖了,為了不找罵,我個人不喜歡而已。言多必失!)

指標的指標,術語叫做指標鏈。一聽鏈,就表明至少有兩個指標。 暫且稱之為A針,B針。A針按三板斧的規則,儲存的是一個資料的地址。而B針儲存的是A針的地址。 繞?看下面:

B --> A --> Data

假設Data所在的地址是123,那麼A儲存的資料就是123. 同時A自己的地址是abc,那麼B儲存的資料就是abc。 如果還有C,那就儲存B的地址,你高興,後面可以跟著一群。

那麼此時此刻,問題來了。 我知道A可以聲明成 var a *int。那麼B呢? *int? 好像不對吧。

大口吸氣,冷靜一下。 想想指標的資料類型。 int是資料類型,*int是指標類型。那麼一個儲存指標類型的指標,也就是疊加一個*int唄。因此B就變成了:

var b **int

如果還有C呢,自個兒寫代碼試試。指標鏈就這麼點需要注意的,如果還不明白,手敲以下代碼跑一下:

package mainimport "fmt"func main() {   var a int   var ptr *int   var pptr **int   a = 3000   ptr = &a   pptr = &ptr   fmt.Printf("Value of a = %d\n", a )   fmt.Printf("Value available at *ptr = %d\n", *ptr )   fmt.Printf("Value available at **pptr = %d\n", **pptr)}

堅持住,已經99%了。看完下面,進度條就跑到100%了(絕不像X雷,卡你99%)。

指標在函數參數中的使用

這裡只是為了湊齊那1%,其實內容已經在:二式<維密>一節,提到過了。只要看準參數是要值傳遞還是引用傳遞,就沒問題。

最後忍不住,來點扯淡的話。 追求知識無可厚非,但現實社會中,金錢是成功與否的唯一標準。所以在學習工作過程中,還是要時時刻刻考慮如何依靠知識來變現。沒有人看的書,等於廁紙。無法變現的知識,等於白學。如果你有好的想法,或者閑得無聊歡迎發郵件給我(ztao8607@gmail.com),沒準火花就迸發於扯淡之間。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.