Go语言中的defer延时机制

    在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) 延迟某个应用

猜你喜欢

转载自blog.csdn.net/sanqima/article/details/108910280