函數是組織好的,可重複利用的、用於執行指定任務的代碼塊。
go語言中支持函數、匿名函數和閉包,而且函數在go語言中屬於「一等公民」。golang
go語言中使用func關鍵字定義函數,具體格式以下:markdown
func 函數名(參數) (返回值){ 函數體 }
其中,閉包
咱們先來定義一個求兩個數之和的函數ide
func sumint(x int, y int) int { return x+y }
函數的參數和返回值都是可選的,例如咱們能夠實現一個既不須要參數也沒有返回值的函數:函數
func sayHello() { fmt.Println("Hello 沙河") }
定義了函數後,咱們經過 函數名()
的方式來調用函數,例如咱們調用上面定義的函數:code
func main() { sayHello() ret := intSum(10, 20) fmt.Println(ret) }
注意,調用有返回值的函數時,能夠不接收其返回值。資源
函數的參數中,若是相鄰變量的類型相同,能夠省略類型,以下:作用域
func intSum(x, y int) int { return x + y }
上面的代碼,函數有兩個參數,這兩個參數的類型均爲int,所以能夠省略x的類型,由於y後面有類型說明,x參數也是該類型。it
可變參數是指函數的參數數量不固定,Go語言中的可變參數,經過在參數名後面加...來標識。
注意:可變參數一般做爲函數的最後一個參數。
舉個例子:for循環
func intSum2(x ...int) int { fmt.Println(x) //x是一個切片 sum := 0 for _, v := range x { sum = sum + v } return sum }
go語言中經過return關鍵字向外輸出函數的返回值。
go語言中的函數支持多個返回值,並在函數體中直接使用這些變量,最後經過return 關鍵詞返回。
func calc(x, y int) (sum, sub int) { sum = x + y sub = x - y return }
因爲go語句中的延遲調研的特性,因此defer語句能很是方便的處理資源釋放問題,好比:資源清理、文件關閉、解鎖及記錄時間等。
在Go語言的函數中return語句在底層並非原子操做,它分爲給返回值賦值和RET指令兩步。而defer語句執行的時機就在返回值賦值操做後,RET指令執行前。具體以下圖所示:
func f1() int { x := 5 defer func() { x++ }() return x } func f2() (x int) { defer func() { x++ }() return 5 } func f3() (y int) { x := 5 defer func() { x++ }() return x } func f4() (x int) { defer func(x int) { x++ }(x) return 5 } func main() { fmt.Println(f1()) fmt.Println(f2()) fmt.Println(f3()) fmt.Println(f4()) }
全局變量是定義在函數外的變量,它在程序整個運行週期內都有效。在函數中能夠訪問到全局變量。
package main import ( "fmt" ) var num int = 10 func testGlobal(){ fmt.Printf("num =%d\n", num) } func main(){ testGlobal() }
局部變量又分爲兩種:函數內定義的變量沒法再該函數外使用,例以下面的示例代碼main函數中沒法使用testLocalvar函數中定義的變量x:
package main import ( "fmt" ) func testLocalvar(){ var x int = 100 fmt.Printf("x=%d\n",x) } func main(){ testLocalvar() fmt.Println(x) }
若是局部變量和全局變量重名,優先訪問局部變量:
package main import ( "fmt" ) var num int = 100 func testNum(){ num := 100 fmt.Printf("num=%d\n",num) } func main(){ testNum() //num =100 }
接下來咱們來看一下語句塊定義的變量,一般咱們會在if條件判斷、for循環、switch語句上使用這種定義變量的方式。
package main import ( "fmt" ) func testLocalvar(x,y int){ fmt.Println(x,y) if x > 0 { z := 100 fmt.Println(z) } fmt.Println(z) //此處沒法使用變量i } func main(){ testLocalvar(1,2) //num =100 }
函數能夠做爲變量進行傳遞:
func main() { f1 := add //將函數add賦值給變量f1 fmt.Printf("type of f1:%T\n", f1) //type of f1:func(int, int) int ret := f1(10, 20) fmt.Println(ret) }
func add(x, y int) int {
return x + y
}
func calc(x, y int, op func(int, int) int) int {
return op(x, y)
}
func main() {
ret2 := calc(10, 20, add)
fmt.Println(ret2) //30
}
函數還能夠做爲返回值,可是在Go語言中函數內部不能再像以前那樣定義函數了,只能定義匿名函數,匿名函數就是沒有函數名的函數,匿名函數的定義格式以下:
func(參數)(返回值){ 函數體 }
匿名函數由於沒有函數名,因此沒辦法像普通函數那樣調用,全部匿名函數須要保存到某個變量或者做爲當即執行函數:
package main import ( "fmt" ) func main(){ add := func(x,y int){ fmt.Println(x+y) } add(10,20) func(x,y int){ fmt.Println(x+y) }(10,20) }
閉包指的是一個函數和與其相關引用環境組合而成的實體。簡單的說,閉包=函數+引用環境。首先咱們看一個實例:
func adder() func(int) int { var x int return func(y int) int { x += y return x } } func main() { var f = adder() fmt.Println(f(10)) //10 fmt.Println(f(20)) //30 fmt.Println(f(30)) //60 f1 := adder() fmt.Println(f1(40)) //40 fmt.Println(f1(50)) //90 }