for循环里面的defer

来源:8-1 defer调用

小肉包哥

2021-07-16

Loop1:
for {
resp, err = http.Get(url)
defer resp.Body.Close()
if err != nil {
logger.Info(err)
} else {
body, err = ioutil.ReadAll(resp.Body)
if resp.StatusCode == 200 {
break Loop1
}
logger.Info(err)
}
logger.Info(err)
time.Sleep( 5 * time.Second)
}

老师,for循环里这样写defer,goland会提示可能发生资源泄露,应该怎么写更合理一点呢

写回答

1回答

ccmouse

2021-07-20

的确会发生泄漏。defer的运行时机是函数返回之前,而不是大括号之前。所以这些Body要等到整个for退出,函数结束才能Close。我来演示一下更好的写法,注意Loop:这些,我们也尽量不要,利用函数来控制跳转以及defer的执行时机。

func getWithRetry(url string) []byte {

     for {

         body, err := get(url)

         if err == nil {

              return body

         }

         logger.Info(err) // 这里应该使用Error或Warning

         time.Sleep(5 * time.Second)

     }

}


func get(url string) ([]byte, error) {

     resp, err := http.Get(url)

     // 先检查错误

     if err != nil {

          return nil, err

     }

     // 再defer Body.Close()

     defer resp.Body.Close()

    

     body, err := ioutil.ReadAll(resp.Body)

     fmt.Print(body) // 这里似乎即使出错也想要打印body。不然的话我们应该先判断StatusCode

     if resp.StatusCode != 200 {

          return nil, fmt.Errorf("bad status: %d", resp.StatusCode)

     }

     return body, nil

}


0
0

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1909 问题

查看课程