◆【函数】

1,定义函数使用func关键字,具体格式如下:

func 函数名(参数)(返回值){

    函数体

}

例:

func sum(x int, y int) (ret int){ #声明参数x,y和返回值ret.
ret = x + y
return
}

2,可变参数

可变参数是指函数的参数数量不固定。在参数名后加...来标识。

可变参数在函数体中是切片类型,通常作为函数的最后一个参数。

例:

func intSum(x ...int) int {
    fmt.Println(x)  
    sum := 0
    for _, v := range x {
        sum = sum + v
    }
    return sum
}

3,多返回值

Go语言中函数支持多返回值,函数如果有多个返回值时必须用()将所有返回值扩起来。

例:

func calc(x, y int) (int, int) {
    sum := x + y
    sub := x - y
    return sum, sub
}

函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return关键字返回。

func calc(x, y int) (sum, sub int) {
    sum = x + y
    sub = x - y
    return
}

4,返回值补充

 当一个函数返回值类型为slice时,nil可以看做是一个有效的slice,没必要显示返回一个长度为0的切片。

func someFunc(x string) []int {
    if x == "" {
        return nil // 没必要返回[]int{}
    }
    ...
}

5,内置函数    介绍

close    主要用来关闭channel。
len        用来求长度,比如string、array、slice、map、channel。
new        用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针。
make    用来分配内存,主要用来分配引用类型,比如chan、map、slice。
append    用来追加元素到数组、slice中。
panic和recover    用来做错误处理。

◆【匿名函数】

func(参数)(返回值){
函数体
}

匿名函数因为没有函数名,所以没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数.

①匿名函数保存到变量,通过变量调用匿名函数。

add := func(x, y int) {
        fmt.Println(x + y)
    }
    add(1, 2)

②自执行函数:匿名函数定义完加()直接执行。

func(x, y int) {
        fmt.Println(x + y)
    }(1, 2)

◆【闭包】

闭包是一个函数和环境的组合。

①定义一个函数,它的返回值是一个函数。

判断一个函数是否是闭包,就看它有无引用函数外部的变量。

//函数名为test;返回值为func(),即函数。
func test() func() {
return func() {  //返回值为匿名函数。
函数体
}
}
func add() func(int) int {
    var x int
    return func(y int) int {
        x += y
        return x
    }
}
func main() {
    var f = add()
    fmt.Println(f(10)) //10
    fmt.Println(f(20)) //30
    fmt.Println(f(30)) //60
  f1 := add()
    fmt.Println(f1(40)) //40
    fmt.Println(f1(50)) //90
}

※变量f就是一个闭包。 在f的生命周期内,变量x也一直有效。  

◆【defer语句】

①在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。

例:

func main() {
    fmt.Println("start")
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
    fmt.Println("end")
}
结果:3,2,1

※由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。  

②defer执行时机

在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。  

③panic/recover

panic可以在任何地方引发,但recover只有在defer调用的函数中有效。

例:

func funcA() {
    fmt.Println("func A")
}
func funcB() {
    defer func() {
        err := recover()
        //如果程序出出现了panic错误,可以通过recover恢复过来
        if err != nil {
            fmt.Println("recover in B")
        }
    }()
 
func funcC() {
    fmt.Println("func C")
}
fuc main() {
    funcA()
    funcB()
    funcC()
}

1,recover()必须搭配defer使用。

2,defer一定要在可能引发panic的语句之前定义