值型別、參考型別
1、在Go語言中,值型別和參考型別有以下特點:
a、值型別:基本資料型別,int,float,bool,string,以及陣列和struct
特點:變數直接存盤值,記憶體通常在堆疊上分配,堆疊在函式呼叫完會被釋放
b、參考型別:指標,slice,map,chan,interface等都是參考型別
特點:變數存盤的是一個地址,這個地址存盤最終的值,記憶體通常在堆上分配,通過GC回收,
- 嚴格來說,Go 語言沒有參考型別,
- 但是我們可以把 map、chan、函式、介面、slice 切片, 稱為參考型別,這樣便于理解,
- 指標型別也可以理解為是一種參考型別,
上面我們提到了堆、堆疊,這里簡單介紹下
記憶體分配中的堆和堆疊:
堆疊(作業系統):由作業系統自動分配釋放 ,存放函式的引數值,區域變數的值等,其操作方式類似于資料結構中的堆疊,堆(作業系統): 一般由程式員分配釋放, 若程式員不釋放,程式結束時可能由OS回收,分配方式倒是類似于鏈表,
值型別和指標型別引數示例:
package main
import "fmt"
func main() {
name := "無塵"
modify1(name)
fmt.Println("name的值為:", name)
modify2(&name)
fmt.Println("name的值為:", name)
}
func modify1(name string) { //值型別
name = "wucs"
}
func modify2(name *string) { //指標型別
*name = "wucs"
}
//運行結果:
//name的值為: 無塵
//name的值為: wucs
參考型別
map
以map型別為引數示例:
package main
import "fmt"
func main() {
m:=make(map[string]int)
m["無塵"] = 18
fmt.Println("無塵的年齡為",m["無塵"])
modify(m)
fmt.Println("無塵的年齡為",m["無塵"])
}
func modify(p map[string]int) {
p["無塵"] =20
}
//運行結果:
//無塵的年齡為 18
//無塵的年齡為 20
- 我們看到,函式 modify 的引數型別為 map ,資料仍然修改成功了,
- 其實,在創建 map 的時候,最終呼叫的是 runtime.makemap 函式,makemap 函式回傳的是一個 *hmap 型別,也就是說回傳的是一個指標,所以我們創建的 map 其實就是一個 *hmap,
- 因為 map 本質上就是個指標,所以通過 map 型別的引數可以修改原始資料,
// makemap implements Go map creation for make(map[k]v, hint).
func makemap(t *maptype, hint int, h *hmap) *hmap{
//省略無關代碼
}
chan
channel 本質上也是個指標,來看原始碼:
func makechan(t *chantype, size int64) *hchan {
//省略無關代碼
}
可以看到創建的 chan 其實是個 *hchan,所以它在引數傳遞中也和 map 一樣,
型別的零值
- 在 Go 語言中,定義變數可以通過
宣告或者通過make、new函式,區別是 make 和 new 函式屬于顯示宣告并初始化, - 如果我們宣告的變數沒有顯示的宣告初始化,那么該變數的默認值就是對于型別的零值,
| 型別 | 零值 |
|---|---|
| 數值型別(int、float等) | 0 |
| bool | false |
| string | ""(空字串) |
| struct | 內部欄位的零值 |
| slice | nil |
| map | nil |
| 指標 | nil |
| 函式 | nil |
| chan | nil |
| interface | nil |
在 Go 語言中,函式的引數傳遞只有值傳遞,而且傳遞的實參都是原始資料的一份拷貝,如果拷貝的內容是值型別的,那么在函式中就無法修改原始資料;如果拷貝的內容是指標(或者可以理解為參考型別 map、chan 等),那么就可以在函式中修改原始資料,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295964.html
標籤:Go
