關於參數傳遞
其實go的參數傳遞,核心就是一句話:go里所有參數傳遞都是值傳遞,既把參數復制一份放到函數里去用。
go的函數傳參,不管參數是什么類型,都會復制一份,然后新的參數在函數內部被使用。
不像其他語言,有的時候傳參只是傳遞一個原來參數的引用(引用和指針的區別,歡迎翻看我上上上上一篇分享),在函數內部操作變量,其實還是操作的原變量。go內不會直接的操作原變量。
關於指針
相比於C里的指針,go內部的指針一個被簡化過的指針,指針可以取值獲取其變量;變量可以取地址獲取一個指針類型的值。 但是不可以對指針執行 地址的加減操作(unsafe.Pointer 可以,不在本次討論范圍之內)。
我覺得這個簡化挺好,保留了參數傳遞時避免大變量的優勢,又去掉了復雜性。
下面來通過實例具體說明
之所以用 切片做示例,是因為 切片是引用類型,也就是說切片內部有一個指針 指向底層放數據的數組。 類似於 一個指針變量。由於它的這個特性,更能說明問題。
錯誤示例1
package main
import "log"
var str []string
func main() {
setVal(str)
log.Println(str)
}
//需要在這里賦值str,但是又不能直接引用 str
func setVal(val []string) {
val = []string{"a", "b"}
}
結果是空數組
雖然切片是引用類型,還是沒有復制成功。 原因就是,在傳參之前 這個切片並沒有被賦值,它內部的指針是一個空的。
傳參的時候,復制了一個切片變量,這個新的變量 指向setVal函數內的實例變量。但是setVal 內的操作並不影響原來的切片變量。
錯誤示例2
package main
import "log"
var str *[]string
func main() {
setVal(str)
log.Println(str)
}
//需要在這里賦值str,但是又不能直接引用 str
func setVal(val *[]string) {
val = &[]string{"a", "b"}
}
這個例子,看似使用了指針,不仔細就得話,可能覺得指針作為參數應該會對原參數產生效果,但其實不會,最后的結果是 nil。
其錯誤原因與上一個例子基本一致,雖然傳遞的是一個 指針。但是 這個指針只是原參數的復制品,一個新的指針,由於參數傳遞時,指針並沒有復制,這個新的指針跟原來的指針毫無關系。
正確版本:
package main
import "log"
var str []string
func main() {
setVal(&str)
log.Println(str)
}
//需要在這里賦值str,但是又不能直接引用 str
func setVal(val *[]string) {
*val = []string{"a", "b"}
}
注意看main 函數,這個時候原參數是一個變量,main 函數內作為參數的是這個變量的地址,同時也是一個指針變量。在setVal內復制了一個指針變量,其值同樣是這個原參數的地址。所以這個例子里setVal 函數內的形參指針進行取值, 會取到原參數,所以其操作會對原參數產生影響。
總結
沒啥好總結的了,總結都被寫在前邊了,還總結個毛線 ~ ~
