Go defer使用

 

defer使用语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//defer后面必须是函数调用语句或方法调用语句,不能是其他语句,否则编译器会出错。
package main
import (
    "fmt"
)
func foo(n int) int {
    defer n++
    //defer fmt.Println(n)
    return n
}
func main() {
    var i int = 100
    foo(i)
}
1
2
3
# command-line-arguments
expression in defer must be function call
syntax error: unexpected ++ at end of statement

  

 

defer 语句的用途

含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。

defer后面的函数在defer语句所在的函数执行结束的时候会被调用;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
import
    "fmt"
)
 
type person struct
    firstName string
    lastName string
}
 
func (p person) fullName() { 
    fmt.Printf("%s %s",p.firstName,p.lastName)
}
 
func main() { 
    p := person {
        firstName: "John",
        lastName: "Smith",
    }
    defer p.fullName()
    fmt.Printf("Welcome "
}

在上面的程序里的第 11 行,a 的初始值为 5。在第 12 行执行 defer 语句的时候,由于 a 等于 5,因此延迟函数 printA 的实参也等于 5。接着我们在第 13 行将 a 的值修改为 10。下一行会打印出 a 的值。该程序输出:

value of a before deferred function call 10  
value of a in deferred function 5

从上面的输出,我们可以看出,在调用了 defer 语句后,虽然我们将 a 修改为 10,但调用延迟函数 printA(a)后,仍然打印的是 5。

 

defer 栈

当一个函数内多次调用 defer 时,Go 会把 defer 调用放入到一个栈中,随后按照后进先出(Last In First Out, LIFO)的顺序执行。

我们下面编写一个小程序,使用 defer 栈,将一个字符串逆序打印。

1
2
3
4
5
6
7
8
9
10
11
12
package main
import
    "fmt"
)
 
func main() { 
    name := "Naveen"
    fmt.Printf("Orignal String: %s\n", string(name))
    fmt.Printf("Reversed String: ")
    for _, v := range []rune(name) {
        defer fmt.Printf("%c", v)
    }}
1
2
Orignal String: Naveen
Reversed String: neevaN

  

defer 的实际应用

  • file对象打开后的自动关闭
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()
 
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()
 
    // other codes
    return io.Copy(dst, src)
}

 在打开输入文件输出文件后,不管后面的代码流程如何影响,这两个文件能够被自动关闭。 

  • mutex对象锁住后的自动释放
1
2
3
4
5
6
func foo(...) {
    mu.Lock()
    defer mu.Unlock()
 
    // code logic
}

确保mu锁能够在函数foo退出之后自动释放。

  • WaitGroup的退出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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")
}

  

 

 

posted @   -零  阅读(746)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示