Go语言中的defer延时机制

    科技2022-07-10  90

        在Go语言中,有时候需要对某个方法、函数或者参数进行延时处理,这时就需要defer关键字。

    defer延时的作用

    一、延迟函数

    可以在函数中添加多个defer语句。 1)当函数执⾏到最后时,这些defer语句会按照逆序执⾏,最后该函数返回。特别是当你在进⾏⼀些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题; 2)如果有很多调⽤defer,那么defer是采⽤后进先出模式; 3)在离开所在的⽅法时,执行defer它自己(报错的时候也会执⾏)

        案例1. 在主函数中延迟调用某个函数 //myDeferFuc.go 在main()里延迟支持func A()

    // myDeferDes project main.go package main import ( "fmt" ) func funA() { fmt.Println("我是funA()...") } func funB() { fmt.Println("我是funB()...") } func funC() { fmt.Println("我是funC()...") } func main() { defer funA() funB() funC() fmt.Println("main is over...") }

        效果如下:

    图(1) 在main()中延迟执行func A()

        案例2. 在子函数中延迟调用某个函数 //myDeferFunc2.go 在子函数中延迟执行func finished()

    // myDeferMax project main.go package main import ( "fmt" ) func finished() { fmt.Println("结束!") } func largest(s []int) { defer finished() fmt.Println("开始寻找最大数...") max := s[0] for _, v := range s { if v > max { max = v } } fmt.Printf("%v中的最大数为:%v\n", s, max) } func main() { s1 := []int{78, 109, 2, 563, 300} largest(s1) }

        效果如下:

    图(2) 在子函数中延迟调用func finished()

    二、延迟方法

    可以使用defer来延迟某个方法的调用

        案例3. 在主函数中延迟调用某个方法 //myDeferMethod.go

    // myDeferMethod project main.go package main import ( "fmt" ) type person struct { firstName string lastName string } func (per person) fullName() { fmt.Printf("%s %s\n", per.firstName, per.lastName) } func main() { per := person{"Steven", "Wang"} defer per.fullName() fmt.Printf("Welcome, ") }

        效果如下:

    图(3) 在主函数中延迟fullName()方法的调用

    三、延迟参数传递(保留参数)

    defer会保留在它声明之前的参数,并在函数的最后才执行。

        案例4. 保留参数a和b, 使用defer //myDeferMethod.go

    // myDeferParam project main.go package main import ( "fmt" ) func printAdd(a, b int) { fmt.Printf("延迟函数中: 参数a,b分别为%d,%d, 两数之和为:%d\n", a, b, a+b) } func main() { a := 5 b := 6 defer printAdd(a, b) //延迟参数a,b的传递 a = 10 b = 7 fmt.Printf("延迟函数执行前: 参数a,b分别为%d,%d, 两数之和为:%d\n", a, b, a+b) }

        效果如下:

    图(4) defer会保留在它声明之前的参数,并在函数的最后才执行

    四、堆栈的推迟

    当⼀个函数有多个延迟调⽤时,它们被添加到⼀个堆栈中,并在Last In First Out(LIFO)后进先出的顺序中执⾏。

        案例5. 利用defer实现字符串倒序 //myDeferReveser.go

    // myDeferHeap project main.go package main import ( "fmt" ) func ReverseString(str string) { for _, v := range []rune(str) { defer fmt.Printf("%c", v) } } func main() { name := "StevenWang欢迎学习区块链" fmt.Println("原始字符串: ", name) fmt.Println("翻转后的字符串: ") ReverseString(name) }

        效果如下:

    图(5) 翻转字符串

    五、延迟某个应用

    推荐使用WaitGroup

        案例6 延迟某个应用 //myDeferApp.go

    // myDeferApp project main.go package main import ( "fmt" "sync" ) type rect struct { length int width int } func (r rect) area(wg *sync.WaitGroup) { defer wg.Done() if r.length < 0 { fmt.Printf("rect %v's length should be greater than zero\n", r) return } if r.width < 0 { fmt.Printf("rect %v's width should be greater than zero\n", r) return } area := r.length * r.width fmt.Printf("rect %v's area %d\n", r, area) } func main() { var wg sync.WaitGroup r1 := rect{-67, 89} r2 := rect{5, -67} r3 := rect{8, 9} rects := []rect{r1, r2, r3} for _, v := range rects { wg.Add(1) go v.area(&wg) } wg.Wait() fmt.Println("All go routines finished executing") }

        效果如下:

    图(6) 延迟某个应用
    Processed: 0.009, SQL: 8