那 Golang 為什麼需要指標呢?這種指針又能有什麼獨特的用途呢? 中(建議學習:go)
為學習引用型別語言的時候,請務必先將其參搞清楚的是值還是引用。
實際上,在大部分引用型語言裡,參數為基本型別時,傳進去的大都是值,也就是另外複製了一份參數到目前的函式呼叫堆疊。參數為高階型別時,傳進去的基本上都是引用。這主要是因為虛擬機器的記憶體管理所導致的。
記憶體管理中的記憶體區域一般包括 heap 和 stack, stack 主要用來儲存目前呼叫堆疊用到的簡單型別資料:string,boolean,int,float 等。
這些類型的記憶體佔用小,容易回收,基本上它們的值和指標所佔用的空間差不多,因此可以直接複製,GC也比較容易做針對性的最佳化。
複雜的高階類型所佔用的記憶體往往相對較大,儲存在heap 中,GC 回收頻率相對較低,代價也較大,因此傳引用/指標可以避免進行成本較高的複製操作,並且節省內存,提高程式運行效率。
因此,在下列情況下可以考慮使用指標:1,需要改變參數的值;2,避免複製運算;3,節省記憶體;
而在Golang 中,具體到高階型別struct,slice,map,也各有不同。實際上,只有 struct 的使用有點複雜,slice,map,chan 都可以直接使用,不用考慮是值還是指標。
Go 有指針,但是沒有指針運算。你不能用指標變數遍歷字串的各個位元組。在 Go 中呼叫函數的時候,我得記得變數是值傳遞的。
透過型別作為前綴來定義一個指標’ * ’:var p * int。現在 p 是一個指向整數值的指標。所有新定義的變數都被賦值為其類型的零值,而指標也一樣。一個新定義的或沒有任何指向的指針,有值 nil。
在其他語言中,這常被叫做空(NULL)指針,在 Go 中就是 nil 。讓指標指向某些內容,可以使用取址運算子( & ),像這樣:
package main import "fmt" func main() { var p *int fmt.Printf("%v\n",p) //← 打印 nil var i int //← 定义一个整形变量 i p = &i //← 使得 p 指向 i, 获取 i 的地址 fmt.Printf("%v\n",p) //打印内存地址 *p = 6 fmt.Printf("%v\n",*p) //打印6 fmt.Printf("%v\n",i) //打印6 }
前面已經說了,沒有指標運算,所以如果這樣寫: *p ,它表示(*p) :先取得指標指向的值,然後再對這個值加一。這裡注意與C語言的區別。
對於Go語言,嚴格意義上來講,只有一種傳遞,也就是按值傳遞(by value)。當一個變數當作參數傳遞的時候,會建立一個變數的副本,然後傳遞給函數或是方法,你可以看到這個副本的位址和變數的位址是不一樣的。
當變數當做指標被傳遞的時候,一個新的指標被創建,它指向變數指向的同樣的記憶體位址,所以你可以將這個指標看成原始變數指標的副本。
當這樣理解的時候,我們就可以理解成Go總是創建一個副本按值轉遞,只不過這個副本有時是變數的副本,有時候是變數指標的副本。
以上是GOLANG 為什麼還有指針的詳細內容。更多資訊請關注PHP中文網其他相關文章!