1. 程式人生 > >golang 結合例項更好的理解引數傳遞和指標

golang 結合例項更好的理解引數傳遞和指標

##### 關於引數傳遞 其實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 函式內的形參指標進行取值, 會取到原引數,所以其操作會對原引數產生影響。 #### 總結 沒啥好總結的了,總結都被寫在前邊了,還總結個