按值傳遞和按引用傳遞
Go 默認使用按值傳遞來傳遞參數,也就是傳遞參數的副本。函數接收參數副本之後,在使用變量的過程中可能對副本的值進行更改,但不會影響到原來的變量,比如 Function(arg1)。
如果你希望函數可以直接修改參數的值,而不是對參數的副本進行操作,你需要將參數的地址(變量名前面添加&符號,比如 &variable)傳遞給函數,這就是按引用傳遞,比如 Function(&arg1),此時傳遞給函數的是一個指針。如果傳遞給函數的是一個指針,指針的值(一個地址)會被複制,但指針的值所指向的地址上的值不會被複制;我們可以通過這個指針的值來修改這個值所指向的地址上的值。(譯者注:指針也是變量類型,有自己的地址和值,通常指針的值指向一個變量的地址。所以,按引用傳遞也是按值傳遞。)
幾乎在任何情況下,傳遞指針(一個32位或者64位的值)的消耗都比傳遞副本來得少。
在函數調用時,像切片(slice)、字典(map)、接口(interface)、通道(channel)這樣的引用類型都是默認使用引用傳遞(即使沒有顯式的指出指針)。
傳遞變長參數
如果函數的最後一個參數是採用 ...type 的形式,那麼這個函數就可以處理一個變長的參數,這個長度可以爲 0,這樣的函數稱爲變參函數。
func myFunc(a, b, arg ...int) {}
這個函數接受一個類似某個類型的 slice 的參數 ,該參數可以通過for 循環結構迭代。
示例函數和調用:
func Greeting(prefix string, who ...string) Greeting("hello:", "Joe", "Anna", "Eileen")
在 Greeting 函數中,變量 who 的值爲 []string{"Joe", "Anna", "Eileen"}。
如果參數被存儲在一個數組 arr 中,則可以通過 arr... 的形式來傳遞參數調用變參函數。
defer 和追蹤
關鍵字 defer 允許我們推遲到函數返回之後(或任意位置執行 return 語句之後)一刻才執行某個語句或函數(爲什麼要在返回之後才執行這些語句?因爲 return 語句同樣可以包含一些操作,而不是單純地返回某個值)。關鍵字 defer 的用法類似於面向對象編程語言 Java 和 C# 的 finally 語句塊,它一般用於釋放某些已分配的資源。
package mainimport "fmt"func main() { function1() }func function1() { fmt.Printf("In function1 at the top\n") defer function2() fmt.Printf("In function1 at the bottom!\n")} func function2() { fmt.Printf("function2: Deferred until the end of the calling function!") }
輸出:
In Function1 at the top In Function1 at the bottom! Function2: Deferred until the end of the calling function!
當有多個 defer 行爲被註冊時,它們會以逆序執行(類似棧,即後進先出):
func f() { for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i) } }
上面的代碼將會輸出:4 3 2 1 0。
將函數作爲參數
package main import ("fmt") func main() { callback(1, Add) } func Add(a, b int) { fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b) } func callback(y int, f func(int, int)) { f(y, 2) // this becomes Add(1, 2) }
閉包
當我們不希望給函數起名字的時候,可以使用匿名函數,例如:func(x, y int) int { return x + y }。
這樣的一個函數不能夠獨立存在(編譯器會返回錯誤:non-declaration statement outside function body),但可以被賦值於某個變量,即保存函數的地址到變量中:fplus := func(x, y int) int { return x + y },然後通過變量名對函數進行調用:fplus(3,4)。
當然,也可以直接對匿名函數進行調用:func(x, y int) int { return x + y } (3, 4)。