Do we have to check for errors when we call Close()?

xuanbao · · 741 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>After reading the comments on this <a href="http://stackoverflow.com/questions/16311232/how-to-pipe-http-response-to-a-file-in-golang/16311368#16311368">stackoverflow answer</a>, It made me wonder how important is it to check for errors when we close a file or the body of an HTTP response.</p> <p>In all the Go code I&#39;ve written before, I&#39;ve never once checked for errors when I close files or http.Response bodies, so reading this made me worry. The examples in the <a href="http://golang.org/pkg/net/http/">Go docs</a> simply call defer resp.Body.Close() without checking for the error so I assumed that this is the correct way. Also, from the top of my head, I can&#39;t remember reading any code where it checked for the error when closing a file or a response body.</p> <p>Do we have to check for these errors and if yes what&#39;s the correct/idiomatic way of doing it?</p> <hr/>**评论:**<br/><br/>dominikh: <pre><p>If it&#39;s a file you&#39;ve written to, check for the error, because it could&#39;ve been delayed until the Close (caching etc.)</p> <p>If you only read from it, the error of Close is irrelevant. Either there&#39;s not going to be one, or there&#39;s no way for you to act on it, anyway. This also/especially goes for the response body.</p></pre>JohnGB: <pre><p>No, you don&#39;t <em>have to</em> check for the errors, but you <em>should</em> check for them.</p> <p>The usual way to handle a Close() is via a defer statement, which makes checking somewhat tricky. The idiomatic way to handle this is to use named return values and defer a func which you can use to check the error. However you don&#39;t want to then replace any other error that may have been returned in the code so you need an additional check.</p> <p>Here&#39;s the way that I do it (stolen from somewhere on the internet, but I can&#39;t recall where exactly):</p> <pre><code>func DoStuff() (s string, err error) { // note the named responses needed for the defer to return an error myFile, err := os.Open(&#34;filename&#34;) if err != nil { return &#34;&#34;, errors.New(&#34;Couldn&#39;t open file: &#34; + err.Error()) } defer func() { if cerr := myFile.Close(); cerr != nil &amp;&amp; err == nil { err = cerr } }() // Do stuff return &#34;someString&#34;, nil } </code></pre></pre>nesigma: <pre><p>Could you please explain the usage of named return values in this case? Why do we need them? What would happen if we had the same code as above without named returns? Thank you.</p></pre>JohnGB: <pre><p>Let&#39;s say that you get to the end of your function and you just do something like &#34;return 42&#34;, and that at some point in your function you had a &#34;defer myFile.Close()&#34;. The execution order would be to return 42 and then call myFile.Close(). So this way, you have no way of modifying what you return based on whether the Close() is successful or not.</p> <p>If on the other hand you&#39;re using named returns, and you have something like &#34;return err&#34;, the defer can modify the returned value before it is actually passed to the calling statement. It&#39;s one of the properties of how defer works in Go.</p> <p>As far as I&#39;m aware, this is the only way to return the result of a defer in a function.</p></pre>mschoch: <pre><p>I would recommend it. I recently started using the errcheck tool (see <a href="https://github.com/kisielk/errcheck">https://github.com/kisielk/errcheck</a>) on the bleve project. At first seemed painful and unnecessary. But, in the end we found several bugs along the way. One common one is when a Close() method is freeing resources, and calling Close() a second time is considered an error. If you ignore these it may seem harmless, but the second call to Close() is usually a good indication that something else is wrong in your program.</p> <p>You asked about idiomatic ways to do this in Go. One common pattern when you are propagating the error is to use named return values. Then in an anonymous deferred function, you can invoke Close() and store the result in a new variable, then, if there was an error, and you weren&#39;t already returning an error, you can assign this one to the named return. You can find an example of this here: <a href="https://github.com/blevesearch/bleve/blob/2af47cea7595510a99a97e86a96308ae67f4755c/index_impl.go#L206-L210">https://github.com/blevesearch/bleve/blob/2af47cea7595510a99a97e86a96308ae67f4755c/index_impl.go#L206-L210</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

741 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传