詳解go中的引用型別
值型別和引用型別
值型別:int、float、bool和string這些型別都屬於值型別,使用這些型別的變數直接指向存在記憶體中的值,值型別的變數的值儲存在棧中。當使用等號=將一個變數的值賦給另一個變數時,如 j = i,實際上是在記憶體中將 i 的值進行了拷貝。可以通過 &i 獲取變數 i 的記憶體地址。 值拷貝
引用型別:特指slice、map、channel這三種預定義型別。引用型別擁有更復雜的儲存結構:(1)分配記憶體 (2)初始化一系列屬性等一個引用型別的變數r1儲存的是r1的值所在的記憶體地址(數字),或記憶體地址中第一個字所在的位置,這個記憶體地址被稱之為指標,這個指標實際上也被存在另外的某一個字中。
兩者的主要區別:拷貝操作和函式傳參。
正文開始重點給大家介紹go中的引用型別。
首先,go中的賦值,都是值傳遞
a := 1
b := ax := Struct{}
y := x
他們都是在記憶體中有獨立空間的,也就是copy 的過程,所以這裡對y的某個屬性的改動,並不會影響x
那麼我們要讓兩個變數指向同一個記憶體怎麼辦呢,可以使用引用型別:
y := &x
這時候,y的型別是*Struct ,這時候我們可以對y進行修改,修改完之後,x也會發現變化,因為y現在是一個引用型別,他指向的是x結構體所在的記憶體
我們可以通過:
y.variable = xxx
來直接呼叫引用型別的結構體賦值,但是要注意的是,這是go的語法糖,他只是幫助我們簡化了通過指標來獲取實際記憶體的過程,完整的寫法應該是這樣的:
(*y).variable = xxx
*y 是對指標的反引用,可以理解為*y == x 。
為什麼設計這個語法糖呢,是因為在go裡面我們是無法直接操作指標,像c++中直接對記憶體地址進行計算進而得到其他記憶體地址的運算,在go裡面是預設不支援的
print(y) // 得到類似0x8123這樣的記憶體地址資料
// 理論上可以得到一個新的記憶體地址,但是在go裡預設是不支援的
newAddr := y + 4
因為無法直接操作地址,所以go就提供語法糖,讓我們在使用引用型別進行操作的時候,預設就是對引用所指向的記憶體地址進行操作。
注意我們是可以對引用型別直接賦值的,但是賦值的型別也必須是引用型別
y = &Struct{} // 這樣是可以的,但是不能是y = Struct{}
a := 1
b := &a
b = 2 // 這是不行的,因為b的型別是 *int
特殊的引用型別
能夠通過make() 函式建立的都是引用型別,比如slice 和map ,slice 雖然看起來像陣列,但是他其實是一個指向陣列記憶體空間的一個指標型別
type Slice struct { point Point // 記憶體地址 len int cap int }
所以我們在執行:
a := []int
b = a
會發現,好像b和a指向的是同一個陣列,事實確實如此。go中所有的賦值都是值傳遞,而slice的賦值,也是對slice物件的一次拷貝,也就是說a和b是不同的slice物件,但是他們指向同一個陣列
同理map也是如此,就不多講來。
總結
到此這篇關於詳解go中的引用型別的文章就介紹到這了,更多相關go中的引用型別內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!