golang爬坑笔记之自问自答系列(8)——关于defer

介绍

defer是Golang中的一大特色,它被称为“延迟函数调用”,关于defer的底层比较复杂,暂时还未深入分析。

此篇未完待续,陆续增加。

用法

语法上,一个defer语句就是一个普通的函数或方法调用,在调用之前加上关键字defer。函数和参数表达式会在语句执行时求值,但是无论是正常情况下,执行return语句或者函数执行完毕,还是不正常的情况下,比如发生宕机,实际的调用推迟到包含defer语句的函数结束后才执行。defer语句没有限制使用次数;执行的时候以调用defer语句顺序的倒序进行(defer执行栈,先进后出)。

示例

package main

import "fmt"

func Plus()  int {
	i := 0
	defer func() {
		i ++
		fmt.Printf("defer1:%d\n",i)
	}()
	defer func() {
		i++
		fmt.Printf("defer2:%d\n",i)
	}()
	return i
}

func main() {
	fmt.Printf("Plus():%d\n",Plus())
}

//输出
//defer2:1
//defer1:2
//Plus():0

可以看到,defer语句是在Plus函数执行return i语句之后开始执行,并按照defer栈的方式依次执行。

注意:defer表达式中可以修改函数中的命名返回值。

我们如果将上述代码稍做修改,Plus返回结果也就不一样了。

package main

import "fmt"

//命名结果变量
func PlusName() (i int)  {
	i = 0
	defer func() {
		i ++
		fmt.Printf("defer1:%d\n",i)
	}()
	defer func() {
		i++
		fmt.Printf("defer2:%d\n",i)
	}()
	return i
}

func main() {
	fmt.Printf("PlusName():%d\n",PlusName())
}
//输出
//defer2:1
//defer1:2
//PlusName():2

常用场景

defer语句的应用场景往往在成对的操作上,比如文件打开关闭,网络连接断开,加锁解锁。

  • 文件关闭
func ReadFile(filename string) ([]byte, error)  {
	f , err := os.Open(filename)
	if err != nil{
		return nil, err
	}
	defer f.Close()
	return ioutil.ReadAll(f)
}
  • 网络断开
func Fetch(url string) ([]byte, error){
	resp, err := http.Get(url)
	if err!= nil{
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}
  • 解锁
type Server struct {
	Address string
	MaxCount int
	CurrentCount int
	Lock sync.Mutex
	Duration time.Duration
	Id int
}

func (rc *Server) WindowAvailable() bool{
	rc.Lock.Lock()
	defer rc.Lock.Unlock()
	return rc.CurrentCount <= rc.MaxCount
}
func (rc *Server) Decrease(){
	rc.Lock.Lock()
	defer rc.Lock.Unlock()
	rc.CurrentCount -= 1
}
func (rc *Server) Increase(){
	rc.Lock.Lock()
	defer rc.Lock.Unlock()
	rc.CurrentCount +=1
}

defer妙用示例

  • 记录函数运行时间
package main

import (
	"fmt"
	"time"
)

func TimeProfile() func(){
	start := time.Now()
	return func() {
		fmt.Printf("time duration:%s",time.Since(start))
	}
}

func work()  {
	time.Sleep(time.Second)
}

func main() {
	defer TimeProfile()()
	work()   //此处可以放置你想测运行时间的函数
}
//输出
//time duration:1.004610669s

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章