1. 程式人生 > >go系列之值傳遞、引用傳遞與指針傳遞

go系列之值傳遞、引用傳遞與指針傳遞

參考 lse make mod s/4 object 引用類型 obj 值傳遞

1、關於值傳遞、引用傳遞與指針傳遞

當一個變量或者新值被創建時, 如果沒有為其明確指定初始值,go語言會自動初始化其值為此類型對應的零值, 各類型零值如下:
false : bool,
0: integer
0.0: float
"": string
nil : pointer, function, interface, slice, channel, map

對於復合類型, go語言會自動遞歸地將每一個元素初始化為其類型對應的零值。比如:數組, 結構體。

nil 是專門為go語言的指針類型和引用類型準備的,go語言的數組和結構體可是值類型, 切片、字典或通道為引用類型。所以如果數組作為函數參數時,因為是值類型, 所以要復制 。

在go語言中沒有引用傳遞,只有值傳遞。

例1:值傳遞

func main() {
	a := []string{"a", "b"}
	test(a)
	fmt.Println(a)
}

func test(b []string) {
	b = []string{"cc", "cc"}
}  

打印出來後值為:[a b],表明在傳遞時是復制了一份單獨的數組結構。

指針傳遞也是值傳遞。

例2:指針傳遞,也是值傳遞

func main() {
	a := &[]string{"a", "b"}
	test(a)
	fmt.Println(*a)
}

func test(b *[]string) {
	b = nil
}

打印出來後為:[a b]。傳遞指針時,能修改指針所指向的值,並不能修改指針本身的值。

傳引用

var a Object
modify(a) // 修改a的值
print(a)

如果函數modify修改a的值, 然後print打印出來的也是修改後的值,那麽就可以認為modify是通過引用的方式使用了參數a。而如上例子證明了指明傳遞是值傳遞。 

例3:引用傳遞

func main() {
    a := new(int)
    fmt.Println(a)
    func() {
        a = nil
    }()
    fmt.Println(a)
}

打印結果為:

0xc042008220
<nil>

關於指針傳遞與引用傳遞參考:https://studygolang.com/articles/4810

2、關於go中的map

go語言中的map不是協程安全的,如果要多個協程對同 一個map進行寫操作,則會出錯:

fatal error: concurrent map writes

舉例:

func main() {
	Map := make(map[int]int)

	for i := 0; i < 100000; i++ {
		go writeMap(Map, i, i)
		go readMap(Map, i)
	}

}

func readMap(Map map[int]int, key int) int {
	return Map[key]
}

func writeMap(Map map[int]int, key int, value int) {
	Map[key] = value
}

因為map為引用類型,所以即使函數傳值調用,參數副本依然指向映射m, 所以N個goroutine並發寫同一個映射m,共享資源會遭到破壞。

解決辦法就是加鎖,或者channel排隊串行化。

go系列之值傳遞、引用傳遞與指針傳遞