[日常] Go语言圣经-Deferred函数

1.只需要在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法。当defer语句被执行时,跟在defer后面的函数会被延迟执行。直到包含该defer语句的函数执行完毕时,defer后的函数才会被执行,不论包含defer语句的函数是通过return正常结束,还是由于panic导致的异常结束

2.defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后

3.defer语句会先调用,defer后面的函数会最后调用,两层函数,配合返回匿名函数函数值实现trace功能
defer trace("bigSlowOperation")()

4.http响应写入文件 n, err = io.Copy(f, resp.Body)

 

练习5.18:不修改fetch的行为,重写fetch函数,要求使用defer机制关闭文件。

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package main
 
//导入io/ioutil和net/http包
import (
        "fmt"
        "io"
        "os"
        //"io/ioutil"
        "net/http"
        "strings"
        //"time"
        "net/url"
)
/*
练习5.18:不修改fetch的行为,重写fetch函数,要求使用defer机制关闭文件。
*/
func main() {
        //开始时间
        //start := time.Now()
        //for循环命令行参数
        for _, u := range os.Args[1:] {
                //加入前缀
                if !strings.HasPrefix(u, "http://") {
                        u = "http://" + u
                }  
                res, err := http.Get(u)
                //判断错误
                if err != nil {
                        //向标准错误流打印信息
                        fmt.Fprintf(os.Stderr, "fetch:%v \n", err)
                        //终止进程
                        os.Exit(1)
                }  
                //使用defer机制
                defer res.Body.Close()
 
                urlObj, _ := url.Parse(u)
                filename := urlObj.Path
                if filename == "/" {
                        filename = "index.html"
                }  
                var f *os.File
                f, err = os.Create(filename)
                //使用defer机制
                /* 
                我们没有对f.close采用defer机制,因为这会产生一些微妙的错误。许多文件系统,尤其是NFS,写入文件时发生的错误会被延迟到文件关闭时反馈。如果没有检查文件关闭时的反馈信息,可能会导致数
据丢失,而我们还误以为写入操作成功。如果io.Copy和f.close都失败了,我们倾向于将io.Copy的错误信息反馈给调用者,因为它先于f.close发生,更有可能接近问题的本质。
                */
                defer f.Close()
                _, err = io.Copy(f, res.Body)
                //判断错误
                if err != nil {
                        //向标准错误流打印信息
                        fmt.Fprintf(os.Stderr, "fetch:%v \n", err)
                        //终止进程
                        os.Exit(1)
                }  
        }  
}

  

posted @   唯一客服系统开发笔记  阅读(494)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2016-04-18 [android] 用fragment创建一个选项卡
2016-04-18 [android] fragment的动态创建
2016-04-18 [Python] 函数基本
2016-04-18 [Python] 使用dict和set
点击右上角即可分享
微信分享提示
1
chat with us