在Go语言中,defer 关键字用于延迟(defer)函数或方法的执行,即在函数执行完毕后再执行被延迟的代码块。defer 语句通常用于资源释放、
清理操作或确保某些代码在函数执行的最后一刻被执行。
下面是对 defer 的几个关键点进行解释:
1.延迟执行:
使用 defer 可以将函数或方法的执行推迟到包含它的函数返回之前。当函数中的 defer 语句被执行时,相应的函数调用被推迟,并被压入一个栈中,直到包含函数返回时才会按照后进先出(LIFO)的顺序执行这些被推迟的函数调用。
2.资源释放:
defer 经常用于释放资源,比如打开的文件、数据库连接或网络连接等。通过在打开资源后使用 defer 来确保在函数返回之前关闭资源,可以避免资源泄漏,即使函数中途发生错误或提前返回,资源也会被正确释放。
3.清理操作:
defer 还可以用于执行一些清理操作,例如解锁互斥锁、关闭通道或恢复(recover)错误处理等。通过在函数开始时使用 defer,可以确保在函数执行结束时进行必要的清理。
4.顺序执行:
多个 defer 语句按照它们的出现顺序进行执行。第一个 defer 语句的函数调用会在最后一个 defer 语句之前执行,即最后一个被推迟的函数调用会最先执行。
package main
import "fmt"
func finished() {
fmt.Println("Finished finding largest")
}
func largest(nums []int) {
defer finished() // 延迟执行
fmt.Println("Started finding largest")
max := nums[0]
for _, v := range nums {
if v > max {
max = v
}
}
fmt.Println("Largest number in", nums, "is", max)
}
func main() {
nums := []int{78, 111, 222, 333}
largest(nums)
}
// Started finding largest
// Largest number in [78 111 222 333] is 333
// Finished finding largest
type Person struct {
firstName string
lastName string
}
func (p Person) fullName() {
fmt.Printf("%s %s", p.firstName, p.lastName)
}
func main() {
p := Person{
firstName: "Mei",
lastName: "Jin",
}
defer p.fullName()
fmt.Printf("Welcome ")
}
// Welcome Mei Jin
func printA(a int) {
fmt.Println("Value of a in deferred function", a)
}
func main() {
a := 5
defer printA(a)
a = 10
fmt.Println("Values of before deferred function call", a)
}
// Values of before deferred function call 10
// Value of a in deferred function 5
func main() {
name := "Like"
fmt.Printf("Original String: %s\n", string(name))
fmt.Printf("Reversed String: ")
for _, v := range name {
defer fmt.Printf("%c", v) // defer表示延迟调用 但是堆栈的数据时后进先出 所以导致字符串反转
}
}
// Original String: Like
// Reversed String: ekiL
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")
}
// rect {8 9}'s area 72
// rect {-67 89}'s length should be greater than zero
// rect {5 -67}'s width should be greater than zero
// All go routines finished executing
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("/test.txt") // 没有该文件
if err != nil {
fmt.Println(err)
return
}
fmt.Println(f.Name(), "Opened successfully")
}
// open test.txt: The system cannot find the file specified.
package main
import (
"errors"
"fmt"
"os"
)
func main() {
f, err := os.Open("/test.txt")
if err != nil {
var pErr *os.PathError
if errors.As(err, &pErr) {
fmt.Println("Failed to open file at path", pErr.Path)
return
}
fmt.Println("Generic error", err)
return
}
fmt.Println(f.Name(), "Opened successfully")
}
// Failed to open file at path /test.txt
package main
import (
"errors"
"fmt"
"net"
)
func main() {
addr, err := net.LookupHost("www.baidu.com")
//addr, err := net.LookupHost("golangbot123.com")
if err != nil {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) {
if dnsErr.Timeout() { // 超时错误
fmt.Println("operation time out")
return
}
if dnsErr.Temporary() { // 临时错误
fmt.Println("Temporary error")
return
}
fmt.Println("Generic DNS error", err) // 没有这个站点
return
}
fmt.Println("Generic error", err)
return
}
fmt.Println(addr) // [180.101.50.242 180.101.50.188]
}
// 没有站点报错 Generic DNS error lookup golangbot123.com: no such host
// 有站点 [180.101.50.242 180.101.50.188]
package main
import (
"errors"
"fmt"
"path/filepath"
)
func main() {
files, err := filepath.Glob("go.mod")
if err != nil {
if errors.Is(err, filepath.ErrBadPattern) {
fmt.Println("Bad pattern error:", err) // syntax error in pattern
return
}
fmt.Println("Generic error:", err) // 类型错误
return
}
fmt.Println("matched files", files) // 正确打印列表 matched files [go.mod]
}
package main
import (
"fmt"
"path/filepath"
)
func main() {
files, _ := filepath.Glob("[") // 匹配错误 如果不展示则找起错误就麻烦了
fmt.Println("matched files", files)
}
// matched files []
package main
import (
"errors"
"fmt"
"math"
)
func circleArea(radius float64) (float64, error) {
if radius < 0 { // 如果小于0则运行以下
return 0, errors.New("Area calculation failed, radius is less than zero")
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -10.00
area, err := circleArea(radius)
if err != nil { // 如果为空
fmt.Println(err)
return
}
fmt.Printf("Area of circle %0.2f", area)
}
// Area calculation failed, radius is less than zero
package main
import (
"fmt"
"math"
)
func circleArea(radius float64) (float64, error) {
if radius < 0 { // 如果小于0则运行以下
return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", radius)
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -10.00
area, err := circleArea(radius)
if err != nil { // 如果为空
fmt.Println(err)
return
}
fmt.Printf("Area of circle %0.2f", area)
}
// Area calculation failed, radius -10.00 is less than zero
package main
import (
"errors"
"fmt"
"math"
)
type areaError struct {
err string
radius float64
}
func (e *areaError) Error() string {
return fmt.Sprintf("radius %0.2f:%s", e.radius, e.err)
}
func circleArea(radius float64) (float64, error) {
if radius < 0 { // 如果小于0则运行以下
return 0, &areaError{
err: "radius is negative",
radius: radius,
}
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -20.0
area, err := circleArea(radius)
if err != nil {
var areaError *areaError
if errors.As(err, &areaError) {
fmt.Printf("Area calculation failed, radius %0.2f is less than zero", areaError.radius)
return
}
fmt.Println(err)
return
}
fmt.Printf("Area of rectangle %0.2f", area)
}
// Area calculation failed, radius -20.00 is less than zero
package main
import (
"errors"
"fmt"
)
type areaError struct {
err string //error description
length float64 //length which caused the error
width float64 //width which caused the error
}
func (e *areaError) Error() string {
return e.err
}
func (e *areaError) lengthNegative() bool {
return e.length < 0
}
func (e *areaError) widthNegative() bool {
return e.width < 0
}
func rectArea(length, width float64) (float64, error) {
err := ""
if length < 0 {
err += "length is less than zero"
}
if width < 0 {
if err == "" {
err = "width is less than zero"
} else {
err += ", width is less than zero"
}
}
if err != "" {
return 0, &areaError{
err: err,
length: length,
width: width,
}
}
return length * width, nil
}
func main() {
length, width := -5.0, -9.0
area, err := rectArea(length, width)
if err != nil {
var areaError *areaError
if errors.As(err, &areaError) {
if areaError.lengthNegative() {
fmt.Printf("error: length %0.2f is less than zero\n", areaError.length)
}
if areaError.widthNegative() {
fmt.Printf("error: width %0.2f is less than zero\n", areaError.width)
}
return
}
fmt.Println(err)
return
}
fmt.Println("area of rect", area)
}
// error: length -5.00 is less than zero
// error: width -9.00 is less than zero
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点点赞收藏+关注谢谢支持 !!!