01简介在Golang语言中,我们可以使用defer关键字在函数(自定义和部分内置)或方法中注册延迟调用(一个或多个),多个延迟调用的执行顺序为先入-后出(FILO)。并且不会受到函数执行退出、显式调用返回和主动(或被动)触发panic的影响。所有注册成功的延迟调用都会被执行,除非在return或函数(或方法)调用os.Exit(1)之后注册了defer。defer注册多个延迟调用,执行顺序为先进后出(FILO)。示例代码:funcmain(){deferfunc(){fmt.Println("A")}()deferfunc(){fmt.Println("B")}()fmt.Println("maingoroutinerunover")//panic("thisisapanicexample")//return}defer如果在return之后定义,等于defer没有注册,不会执行。示例代码:funcmain(){fmt.Println("main")returndeferfunc(){fmt.Println("A")}()}在defer所在的函数或方法中,如果调用了os.Exit(1),defer会注册,也不会执行。示例代码:funcmain(){deferfunc(){fmt.Println("A")}()fmt.Println("main")os.Exit(1)}函数和方法中必须使用defer,defer必须后面跟一个函数(自定义和一些内置函数)或方法,defer函数的实参是值的副本。示例代码funcmain(){a:=0deferfunc(numint){fmt.Println("deferfunc()",num)}(a)a++fmt.Println(a)}02使用关键字defer(customandpartiallybuilt-in)ormethod,因为它不会受到函数执行结束、显式调用返回和主动(或被动)触发panic的影响,通常用于防止忘记释放资源和捕获panic(在同一个goroutine)以防止应用程序崩溃和退出的场景。示例代码:funcmain(){f,err:=os.OpenFile("text.txt",os.O_WRONLY|os.O_APPEND|os.O_CREATE,0755)iferr!=nil{fmt.Println(err)}deferf。Close()n,err:=f.WriteString("thisisatextfile\t")iferr!=nil{fmt.Println(err)}fmt.Println(n)}看了上面的代码,我们使用defer来延迟调用releaseresources,防止忘记释放资源(关闭文件或解锁),通常defer会放在错误检查之后。示例代码:funcmain(){deferfunc(){iferr:=recover();err!=nil{fmt.Println("thisisapanic")}}()panic("thisisatesestpanic")fmt.Println("main")}看了上面的代码,我们使用defer配合recover函数来拦截panic(在同一个goroutine中),防止程序崩溃退出。03注意事项虽然使用defer可以防止忘记释放资源和拦截panic(在同一个goroutine中)防止应用崩溃退出。然而,延迟也有副作用。会延迟资源的释放。尽量不要在for循环中使用defer。与不使用defer调用的函数(自定义和部分内置)或方法相比,defer也有一定的性能损失。Golang语言官方还在golang1.13和golang1.14中优化了defer的性能。相较于defer的性能损失,defer带来了代码更优雅、可读性和健壮性等优势。我认为defer总的来说是利大于弊,它给gopher带来的好处多于它付出的代价。.因此,我建议大家尽量使用defer。另一件需要注意的事情是,我们不应该使用defer来调用具有返回值的自定义函数或方法。返回值会丢失,可能给应用程序带来意想不到的错误。04总结在本文中,我们介绍了defer的执行机制、使用场景和注意事项,并给出了相应的示例代码。通常我们在Golang语言开发中使用defer来防止忘记释放资源(关闭文件或解锁)和捕获panic(在同一个goroutine中)以防止应用崩溃退出。本文转载自微信公众号《Golang语言开发栈》,可通过以下二维码关注。转载本文请联系Golang语言开发栈公众号。
