不像 Java 和 .NET,Go 語言為程序員提供了控制數(shù)據(jù)結(jié)構(gòu)的指針的能力;但是,你不能進(jìn)行指針運(yùn)算。通過給予程序員基本內(nèi)存布局,Go 語言允許你控制特定集合的數(shù)據(jù)結(jié)構(gòu)、分配的數(shù)量以及內(nèi)存訪問模式,這些對構(gòu)建運(yùn)行良好的系統(tǒng)是非常重要的:指針對于性能的影響是不言而喻的,而如果你想要做的是系統(tǒng)編程、操作系統(tǒng)或者網(wǎng)絡(luò)應(yīng)用,指針更是不可或缺的一部分。
程序在內(nèi)存中存儲它的值,每個內(nèi)存塊(或字)有一個地址,通常用十六進(jìn)制數(shù)表示,如:0x6b0820?或?0xf84001d7f0。
Go 語言的取地址符是?&,放到一個變量前使用就會返回相應(yīng)變量的內(nèi)存地址。
下面的代碼片段可能輸出?An integer: 5, its location in memory: 0x6b0820(這個值隨著你每次運(yùn)行程序而變化)。
var i1 = 5
fmt.Printf("An integer: %d, it's location in memory: %p\n", i1, &i1)
這個地址可以存儲在一個叫做指針的特殊數(shù)據(jù)類型中,在本例中這是一個指向 int 的指針,即?i1:此處使用 *int 表示。如果我們想調(diào)用指針 intP,我們可以這樣聲明它:
?var intP *int? ?然后使用 intP = &i1 是合法的,此時 intP 指向 i1。
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)}
輸出: An integer: 5, its location in memory: 0x24f0820 The value at memory location 0x24f0820 is 5
?Go 語言和 C、C++ 以及 D 語言這些低級(系統(tǒng))語言一樣,都有指針的概念。
但是對于經(jīng)常導(dǎo)致 C 語言內(nèi)存泄漏繼而程序崩潰的指針運(yùn)算
(所謂的指針?biāo)惴?,如?pointer+2 ,移動指針指向字符串的字節(jié)數(shù)或數(shù)組的某個位置)
是不被允許的。Go 語言中的指針保證了內(nèi)存安全,更像是 Java、C# 和 VB.NET 中的引用。
因此 c = *p++ 在 Go 語言的代碼中是不合法的。指針的一個高級應(yīng)用是你可以傳遞一個變量的引用(如函數(shù)的參數(shù)),這樣不會傳遞變量的拷貝。指針傳遞是很廉價的,只占用 4 個或 8 個字節(jié)。當(dāng)程序在工作中需要占用大量的內(nèi)存,或很多變量,或者兩者都有,使用指針會減少內(nèi)存占用和提高效率。被指向的變量也保存在內(nèi)存中,直到?jīng)]有任何指針指向它們,所以從它們被創(chuàng)建開始就具有相互獨(dú)立的生命周期。
另一方面(雖然不太可能),由于一個指針導(dǎo)致的間接引用(一個進(jìn)程執(zhí)行了另一個地址),指針的過度頻繁使用也會導(dǎo)致性能下降。
指針也可以指向另一個指針,并且可以進(jìn)行任意深度的嵌套,導(dǎo)致你可以有多級的間接引用,但在大多數(shù)情況這會使你的代碼結(jié)構(gòu)不清晰。
如我們所見,在大多數(shù)情況下 Go 語言可以使程序員輕松創(chuàng)建指針,并且隱藏間接引用,如:自動反向引用。對一個空指針的反向引用是不合法的,并且會使程序崩潰。?