golang(二)

基本結構和基本數據類型 程序員

指針算法

不像 Java 和 .NET,Go 語言爲程序員提供了控制數據結構的指針的能力;可是,你不能進行指針運算。
經過給予程序員基本內存佈局,Go 語言容許你控制特定集合的數據結構、分配的數量以及內存訪問模
式,這些對構建運行良好的系統是很是重要的:指針對於性能的影響是不言而喻的,而若是你想要作的是
系統編程、操做系統或者網絡應用,指針更是不可或缺的一部分。
編程


因爲各類緣由,指針對於使用面向對象編程的現代程序員來講可能顯得有些陌生,不過咱們將會在這一小
節對此進行解釋,並在將來的章節中展開深刻討論。
數組


程序在內存中存儲它的值,每一個內存塊(或字)有一個地址,一般用十六進制數表示,如: 0x6b0820 或
0xf84001d7f0 。
安全


Go 語言的取地址符是 & ,放到一個變量前使用就會返回相應變量的內存地址。
下面的代碼片斷(示例 4.9 pointer.go)可能輸出 An integer: 5, its location in memory: 0x6b0820
(這個值隨着你每次運行程序而變化)。
網絡

var i1 = 5
fmt.Printf("An integer: %d, it's location in memory: %p\n", i1, &i1)

 

這個地址能夠存儲在一個叫作指針的特殊數據類型中,在本例中這是一個指向 int 的指針,即 i1 :此處
使用 *int 表示。若是咱們想調用指針 intP,咱們能夠這樣聲明它:
數據結構


var intP *int
ide

而後使用 intP = &i1 是合法的,此時 intP 指向 i1。(指針的格式化標識符爲 %p )intP 存儲了 i1 的內存地址;函數

它指向了 i1 的位置,它引用了變量 i1。一個指針變量能夠指向任何一個值的內存地址 它指向那個值的內存地址,佈局

在 32 位機器上佔用 4 個字節,在 64 位機器上佔用 8 個字節,而且與它所指向的值的大小無關。固然,

能夠聲明指針指向任何類型的值來代表它的原始性或結構性;你能夠在指針類型前面加上 * 號(前綴)

來獲取指針所指向的內容,這裏的* 號是一個類型更改器。使用一個指針引用一個值被稱爲間接引用。

當一個指針被定義後沒有分配到任何變量時,它的值爲 nil 。一個指針變量一般縮寫爲 ptr 。

注意事項
在書寫表達式相似 var p *type 時,切記在 * 號和指針名稱間留有一個空格,由於 - var p*type 是
語法正確的,可是在更復雜的表達式中,它容易被誤認爲是一個乘法表達式!
注意:

符號 * 能夠放在一個指針前,如 *intP ,那麼它將獲得這個指針指向地址上所存儲的值;這被稱爲反引用
(或者內容或者間接引用)操做符;另外一種說法是指針轉移。
對於任何一個變量 var, 以下表達式都是正確的: var == *(&var) 。

如今,咱們應當能理解 pointer.go 中的整個程序和他的輸出:


示例 pointer.go:

package main
import "fmt"
func main() {
    var i1 = 5
    fmt.Printf("An integer: %d, its location in memory: %p\n", i1, &i1)
    var intP *int
    intP = &i1
    fmt.Printf("The value at memory location %p is %d\n", intP, *intP)
}
pointer.go

    輸出:

 

 

 

 程序 string_pointer.go 爲咱們展現了指針對string的例子。
它展現了分配一個新的值給 *p 而且更改這個變量本身的值(這裏是一個字符串)。

 

  示例  string_pointer.go

package main
import "fmt"
func main() {
    s := "good bye"
    var p *string = &s
    *p = "ciao"
    fmt.Printf("Here is the pointer p: %p\n", p) // prints address
    fmt.Printf("Here is the string *p: %s\n", *p) // prints string
    fmt.Printf("Here is the string s: %s\n", s) // prints same string
}
string_pointer.go

     輸出:

 

 

 經過對 *p 賦另外一個值來更改「對象」,這樣 s 也會隨之更改 。

注意事項
你不能獲得一個文字或常量的地址,例如

 

 

 注意事項
你不能獲得一個文字或常量的地址,例如 :

const i = 5
ptr := &i //error: cannot take the address of i
ptr2 := &10 //error: cannot take the address of 10

因此說,Go 語言和 C、C++ 以及 D 語言這些低級(系統)語言同樣,都有指針的概念。可是對於常常導
致 C 語言內存泄漏繼而程序崩潰的指針運算(所謂的指針算法,如: pointer+2 ,移動指針指向字符串
的字節數或數組的某個位置)是不被容許的。Go 語言中的指針保證了內存安全,更像是 Java、C# 和VB.NET 中的引用。
所以 c = *p++ 在 Go 語言的代碼中是不合法的。

指針的一個高級應用是你能夠傳遞一個變量的引用(如函數的參數),這樣不會傳遞變量的拷貝。指針傳
遞是很廉價的,只佔用 4 個或 8 個字節。當程序在工做中須要佔用大量的內存,或不少變量,或者二者都
有,使用指針會減小內存佔用和提升效率。被指向的變量也保存在內存中,直到沒有任何指針指向它們,
因此從它們被建立開始就具備相互獨立的生命週期。


另外一方面(雖然不太可能),因爲一個指針致使的間接引用(一個進程執行了另外一個地址),指針的過分
頻繁使用也會致使性能降低。


指針也能夠指向另外一個指針,而且能夠進行任意深度的嵌套,致使你能夠有多級的間接引用,但在大多數
狀況這會使你的代碼結構不清晰。


如咱們所見,在大多數狀況下 Go 語言可使程序員輕鬆建立指針,而且隱藏間接引用,如:自動反向引用。
對一個空指針的反向引用是不合法的,而且會使程序崩潰:

  示例 testcrash.go:

package main
func main() {
var p *int = nil
*p = 0
}//
in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
// runtime error: invalid memory address or nil pointer dereference
testcrash.go
相關文章
相關標籤/搜索