Error best practices in libraries

agolangf · · 409 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I often find myself in a situation where I would like to handle an error that is returned from a library that I am using, only to find that the error is created dynamically with something like fmt.Errorf, or if it is staticly defined, it is not publicly exported.</p> <p>At that point, the only thing that can be done to handle the error is to match on the error string, but this feels brittle, and if a format string is used to provide something like an id it becomes almost unteneble. My feeling is that errors should almost ALWAYS be publicly exported, statically declared parts of a package to allow the caller to handle them appropriately if need be. If the errors have information that need to be added to them a custom error type should be created, and the custom information should be a field member on that specific type of error.</p> <p>Some people object to this idea on the grounds that some errors should not be considered part of the API of the package so that they can be removed or changed if need be. I find this to be a loathesome and stupid idea.</p> <p>Are there any established best practices for generating errors in golang. Is anyone sympathatic to the objection raised above?</p> <hr/>**评论:**<br/><br/>kardianos: <pre><p>If you want users to be able to distinguish errors, then yeah, do that. I do that here, I&#39;ve got a number of errors (too may really) that are exported so the consumer of the package can make decisions based on which error is returned. <a href="https://github.com/kardianos/govendor/blob/master/context/copy.go" rel="nofollow">https://github.com/kardianos/govendor/blob/master/context/copy.go</a></p> <p>But that&#39;s abnormal. Most of the time the calling site (where the error came from) is important. What you export and type and what you just fmt.Error is a judgement call. You don&#39;t want to export errors that don&#39;t matter (&gt; API surface, needless clutter). If you need to differentiate an error, open a bug on the package and explain why you think that error should be typed.</p></pre>abcded1234234: <pre><blockquote> <p>If you need to differentiate an error, open a bug on the package and explain why you think that error should be typed.</p> </blockquote> <p>This is just a comment to support this advice ;)</p></pre>djherbis: <pre><p>I think the std. lib has a decent approach to this.</p> <p>Certain errors like <a href="https://golang.org/pkg/io/#EOF" rel="nofollow">io.EOF</a> are always the same and exported directly.</p> <p>Errors which might contain some contextual /more info have their own type like <a href="https://golang.org/pkg/net/#AddrError" rel="nofollow">net.AddrErr</a> or provide methods to obtain more info about a given error like <a href="https://golang.org/pkg/os/#IsExist" rel="nofollow">os.IsExist</a>.</p> <p>Overall though, I agree that people should avoid using fmt.Errorf() as an internal library error. Probably it&#39;s fine for an application error though.</p></pre>barsonme: <pre><p>If I need somebody to be able to check the type of an error, i&#39;ll export it (e.g. io.EOF)</p> <p>If the meaning of the error could vary (e.g. error codes) I&#39;ll create a type that has a method or member that contains the meaning of the error.</p> <p>Otherwise, fmt.Errorf/errors.New works well.</p></pre>icholy: <pre><p>If there&#39;s a specific error that you want to be exported and you have a good use case, I doubt the package maintainer would be opposed to the change. I can&#39;t think of an instance where a change like that wouldn&#39;t be backwards compatible. Exporting every possible error would be overkill and it makes more sense to keep it simple until you know you need to make a distinction between them. Go&#39;s interfaces let things like this grow organically.</p></pre>elithrar_: <pre><p><a href="http://dave.cheney.net/2014/12/24/inspecting-errors" rel="nofollow">http://dave.cheney.net/2014/12/24/inspecting-errors</a> is a good read on the subject. </p> <p>In my experience, static ErrXXXX strings are fine for smaller packages, but I tend to lean towards writing an <code>Error</code> interface (similar to <a href="https://golang.org/pkg/net/#Error" rel="nofollow">https://golang.org/pkg/net/#Error</a>) with appropriate methods to inspect the type of error. e.g.</p> <pre><code>// For an imaginary SQL library type Error interface { error Driver() bool Syntax() bool // Wrap the underlying error; e.g. a pg.Error, net.Error, etc Cause() error } </code></pre> <p>This allows the caller to inspect the error in a non-brittle (read: string comp) manner, special case the errors they care about, and extract the root cause from an underlying library if necessary. </p></pre>

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

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