注意 Go中没有函数重载
函数定义
func name(arg1 type,arg2 type...) return_type{
}
命名返回值
package main
import "fmt"
func add_all(arr []int) (sum int) {
for _, v := range arr {
sum += v
}
return
}
func main() {
a := [...]int{1, 2, 3, 4, 5}
fmt.Println(add_all(a[:]))
}
多返回值
package main
import "fmt"
func add_all(arr []int) (indexsum, sum int) {
for i, v := range arr {
indexsum += i
sum += v
}
return
}
func main() {
a := [...]int{1, 2, 3, 4, 5}
fmt.Println(add_all(a[:]))// 10 15
}
变长参数
package main
import "fmt"
func add_all(cnt int, arr ...int) (sum int) { //变长参数只能放在最后面
for i := 0; i < cnt; i++ {
sum += arr[i]
}
return
}
func main() {
fmt.Println(add_all(3, 1, 2, 3))
}
闭包函数
匿名函数
go中函数也是一个类型,可以达到在函数中定义函数的效果。
package main
import "fmt"
func main() {
var x int = 1
var fun = func(a int) (ans int) {
x = 2
ans = a * a
return
}
fmt.Println(fun(2), x)
}
package main
import "fmt"
func f(i int) func() int {
return func() int {
i++
return i
}
}
func main() {
var c = func(a, b int) (sum int) {
sum = a + b
return
}(1, 2)
fmt.Println(c)//3
}
闭包
package main
import "fmt"
func f(i int) func() int {
return func() int {
i++
return i
}
}
func main() {
var c = f(0)
fmt.Println(c(), c())//1,2
}
上面的例子中,i
这个变量escape
了,到了heap
中,所以每次调用的都是同一个i
,
其实返回的不只有这个函数,还返回了函数外层的变量引用,实际上是返回了一个结构体,里面有函数和变量的地址。当调用函数的时候就是在调用这个匿名函数
识别出变量需要在堆上分配,是由编译器的一种叫escape analyze的技术实现的。如果输入命令:
go build --gcflags=-m main.go
package main
import "fmt"
func f(i int) func() int {
return func() int {
i++
return i
}
}
func main() {
var c = f(0)
var d = f(0)
fmt.Println(c(), d())// 1 1
}
c
和d
处在两个不同的环境,所以不会影响别人的i
。返回闭包时并不是单纯返回一个函数,而是返回了一个结构体,记录下函数返回地址和引用的环境中的变量地址。
异常处理
defer
defer关键字会将函数压入栈中,等到外层函数退出即将时再从栈中取出运行
package main
import "fmt"
func main() {
defer fmt.Print("B")
fmt.Println("A")
}// A B