go基础之函数,匿名函数,defer,panic/recover

函数
函数是一个组织好的,可以重复使用的,用于执行,指定任务的代码块。
Go语言支出,函数,匿名函数和闭包

package main

import (
    "fmt"
"strings"
)
func main() {
    
    
    // 定义函数的格式
    // func 函数名(参数)(返回值){
    
    
    // }
    //通过函数名就可以调用函数,函数有参数的情况下,
    // 必须填写参数,调用函数的结果,就是返回值
    fmt.Println("fu1函数", fu1(3, 2))
    //可变参数的函数调用,除了第一个参数,其他的参数都算作是,第二个参数的
    fmt.Println("fu2函数", fu2(1, 2, 3, 4, 5, 6))
    //多个返回值
    o, p := fu3()
    fmt.Println(o, p)
    l, n := fu4()
    fmt.Println(l, n)
    //函数作为函数的参数和返回值
    ff := fu5(fu6)
    //ff是fu5的返回值,是一个func(x int)int类型的函数
    fmt.Println(ff(1))
    testAdd()
    testMakeSuffixFunc()
    testCalc()
}
// 定义一个函数,返回参数一加上参数二
// 函数参数中,相邻的两个参数的类型相同可以简写,如下:
func fu1(i, o int) (x int) {
    
    
    x = i + o
    return
}
// 可变参数的函数,如下函数中,参数o是一个可变长度的参数,
// o的类型是一个切片,可变长度的参数,只能写在所有参数中的最后一个
func fu2(i int, o ...int) (x int) {
    
    
    for _, v := range o {
    
    
        i += v
    }
    x = i
    return
}
//多返回值
//返回值,没有命名变量只写了类型,那么rutern后面就行跟上变量
func fu3() (int, int) {
    
    
    return 2, 3
}
//返回命名的变量
//返回值中,命名了变量,那么return后面就不用写变量
//在参数,和返回值中命名好的变量可以直接使用,不用再命名了
func fu4() (x, y int) {
    
    
    x = 3
    y = 3
    return
}
// 函数还可以作为函数的返回值和变量
func fu5(f func(int, int) int) (f1 func(int) int) {
    
    
    a, p := 1, 2
    o := f(a, p)
    fmt.Println(o)
    //定义了一个匿名函数
    f1 = func(i int) int {
    
    
        return i
    }
    return
}
func fu6(o, p int) int {
    
    
    return o * p
}
//闭包
//闭包指的是一个函数,引用了他外部的数据
//案例一
func adder(x int) func(i int) int {
    
    
    x += x
    return func(i int) int {
    
    
        x += i
        return x
    }
}
//变量adder是一个函数并且他引用了其外部作用域中的x变量,此时adder就是一个闭包
//在adder变量的生命周期内,x一直有效
func testAdd() {
    
    
    adder := adder(5)
    fmt.Println("闭包案例一")
    fmt.Println(adder(2))
    fmt.Println(adder(3))
    fmt.Println(adder(4))
}
//闭包
//案例二
func makeSuffixFunc(i string) func(s string) string {
    
    
    return func(s string) string {
    
    
        if strings.HasSuffix(s, i) {
    
    
            return s
        }
        s += i
        return s
    }
}
//调用两次makeSuffixFunc函数,返回两个函数,两个函数之间不会互相冲突
func testMakeSuffixFunc() {
    
    
    fmt.Println("闭包案例二")
    suffix1 := makeSuffixFunc(".txt")
    fmt.Println(suffix1("fdsfsdf"))
    suffix2 := makeSuffixFunc(".JPG")
    fmt.Println(suffix2("fdsfsdf"))
}
//闭包
//案例三
func calc(i int) (func(int) int, func(int) int) {
    
    
    add := func(x int) int {
    
    
        i += x
        return i
    }
    sub := func(x int) int {
    
    
        i -= x
        return i
    }
    return add, sub
}
//因为变量add和sub,一直在操作同一个变量i,所以只要add和sub一直被调用,
// 那么i一直存在并且会将i以类似缓存的方式保存起来
func testCalc() {
    
    
    fmt.Println("闭包案例三")
    add, sub := calc(10)
    fmt.Println(add(1), sub(2))
    fmt.Println(add(3), sub(4))
    fmt.Println(add(5), sub(6))
}

defer语句
Go语言中的defer会将起后面跟随的语句进行延迟执行,在defer归属的函数即将返回值,将延迟执行的defer语句定义的逆序执行,先defer的语句,后执行,后defer的语句先执行
defer语句执行的时机

在Go语言中,return的底层并不是一个原子性的操作,分为返回值赋值和真正的执行return命令,defer就是在返回值赋值之后,和return之前

package main

import "fmt"
func main() {
    
    
    fmt.Println(def1())
    fmt.Println(def2())
    fmt.Println(def3())
    fmt.Println(def4())
    def5()
}
//defer后的函数必须被调用
//return一共三步
// 1.把x值赋给返回值
// 2.defer语句中给x+1,并没有给返回值加一
// 3.执行retuen命令
func def1() int {
    
    
    x := 5
    defer func() {
    
    
        x++
    }()
    return x
}
//return一共三步
// 1.把5值赋给返回值x
// 2.defer语句中给x+1,此时x就是返回值,所以此时x就是6
// 3.执行retuen命令
func def2() (x int) {
    
    
    defer func() {
    
    
        x++
    }()
    return 5
}
//return一共三步
// 1.把x值赋给返回值y
// 2.defer语句中给x+1,此时y是返回值,所以y等于5
// 3.执行retuen命令
func def3() (y int) {
    
    
    x := 5
    defer func() {
    
    
        x++
    }()
    return x
}
//return一共三步
// 1.把5值赋给返回值x
// 2.defer语句中给x+1,此时x是匿名函数中的x,不会影响到def4中的x,所以返回值为5
// 3.执行retuen命令
func def4() (x int) {
    
    
    defer func(x int) {
    
    
        x++
    }(x)
    return 5
}
//面试题
func calc(index string, a, b int) int {
    
    
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}
func def5() {
    
    
    x := 1
    y := 2
    //defer执行之前会确认函数中所有的参数,再进行压栈,之后参数的改动,不影响defer后的函数
    defer calc("AA", x, calc("A", x, y)) //calc("AA",1,3)
    x = 10
    defer calc("BB", x, calc("B", x, y)) //calc("BB",10,12)
    y = 20
}

panic/recover
Go语言中目前没有异常机制,但是使用panic/recover模式来处理异常,panic可以在任何地方引发,但是recover只能在defer调用的函数中使用。

package main

import "fmt"
func main() {
    
    
    f1()
    f2()
    f3()
}
func f1() {
    
    
    fmt.Println("a")
}
//defer语句会在panic抛异常之前运行
func f2() {
    
    
    fmt.Println("b")
    defer func() {
    
    
        //程序没有终止,被重新启动了
        recover()
    }()
    panic("Error")
}
func f3() {
    
    
    fmt.Println("c")
}

猜你喜欢

转载自blog.csdn.net/weixin_44865158/article/details/114640986