<p>I've wrote a little library that extends standard sync package. Now it contains <strong>AdwancedWaitGroup</strong> and <strong>Semaphore</strong>. With AdwancedWaitGroup you can add timeouts or cancel wait process by context. Also you can get all errors and panics that throws in execution process.
<a href="https://github.com/o1egl/syncx" rel="nofollow">https://github.com/o1egl/syncx</a></p>
<hr/>**评论:**<br/><br/>tv64738: <pre><p>Use this instead: <a href="https://godoc.org/golang.org/x/sync/errgroup" rel="nofollow">https://godoc.org/golang.org/x/sync/errgroup</a></p></pre>ZetaHunter: <pre><p>To me your errors look slightly awkward, usually when I write or read error messages they are all lowercase and no punctuation.</p></pre>DenzelM: <pre><p>To expand upon this, <code>errors.New</code> is a code smell. As a client/user of the library, there is no easy way to get information about an error without resorting to ugly string manipulations that then force the client to depend upon an implementation-detail. That's bad. </p>
<p>Be explicit when returning your errors. <code>errors.New</code> should only be used when it's <em>not</em> expected that the client/user will work with the error.</p></pre>shovelpost: <pre><blockquote>
<p>To expand upon this, errors.New is a code smell.</p>
</blockquote>
<p>Why is that? Isn't <code>errors.New</code> equivalent to <code>fmt.Errorf</code>? As far as I've seen they are both used in the standard library to return error messages.</p></pre>DenzelM: <pre><p>Correct, <code>errors.New</code> and <code>fmt.Errorf</code> should only be used when you <em>don't</em> expect the client/user will work with the error. It's a code smell otherwise.</p>
<p>See <a href="https://golang.org/pkg/net/http/#pkg-variables" rel="nofollow">net/http</a>: not only does it allow you to catch a type of error, i.e. <code>ProtocolError</code>, you can also handle them by name, e.g., <code>ErrNotSupported</code>, <code>ErrUnexpectedTrailer</code>, etc. You'll notice that they use <code>errors.New</code> with some of them even:</p>
<pre><code>var ErrContentLength = errors.New("http: wrote more than the declared Content-Length")
</code></pre>
<p>So that when they return <code>ErrContentLength</code>, the client/user can tell. As another example, you can see that the http server returns a named error:</p>
<pre><code>select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
</code></pre>
<p>Once again, so that the client/user can distinguish between what error was returned in case they want to implement some logic. Think about it, if instead the code was:</p>
<pre><code>select {
case <-srv.getDoneChan():
return errors.New("http: Server closed")
default:
}
</code></pre>
<p>Then how does the user work with this error? They have to do a string manipulation, and now they're dependent upon an implementation detail. Namely, the words in your error string; if you update anything in that error string, then you risk breaking end-users' code.</p>
<p>That doesn't mean the standard library doesn't use <code>errors.New</code> and <code>fmt.Errorf</code> in returns, as you say. It does. But only in two cases:</p>
<ol>
<li>When the user is not expected to handle the error explicitly</li>
<li>When there is only one error to return and thus it is clear in context</li>
</ol>
<p>For example, <a href="https://golang.org/pkg/bytes/" rel="nofollow">bytes</a> defines <code>ErrTooLarge</code> using the idiomatic style described earlier, however it also returns <code>errors.New</code> directly in a function. Specifically, <a href="https://golang.org/src/bytes/buffer.go?s=10793:10828#L333" rel="nofollow">UnreadRune</a> because as per #2 there is only one error UnreadRune can return, thus making its meaning clear in context:</p>
<pre><code>func (b *Buffer) UnreadRune() error {
if b.lastRead <= opInvalid {
return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
}
if b.off >= int(b.lastRead) {
b.off -= int(b.lastRead)
}
b.lastRead = opInvalid
return nil
}
</code></pre>
<p>Rule of thumb: name your errors. It's better for everyone.</p></pre>shovelpost: <pre><p>Thanks! I can't upvote this enough.</p>
<blockquote>
<p>not only does it allow you to catch a type of error, i.e. ProtocolError, you can also handle them by name</p>
</blockquote>
<p>I've heard that handling errors by name or type <a href="https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully" rel="nofollow">is not considered a very good practice</a>. What is your opinion on this?</p></pre>DenzelM: <pre><p>While I agree with his ordering: behavior > type > sentinel > Error(), it's foolhardy to treat his prescriptions as absolutes. There are times when it absolutely makes sense to return error types... and depend upon the package for those error types because, well, that's the definition of a dependency.</p>
<p>I don't enjoy the line of reasoning that one should seek to duplicate interface definitions across the code base (in the case of behavior errors) just to avoid increasing the "surface area" of your imports. Why? Because you're eliding the actual dependency that exists by definition! So what happens when the error's behavioral interface is updated? Now you must update the interface definition in N places, instead of 1. You get all the benefits of duplication because you've chosen to describe a dependency implicitly instead of explicitly in the form of a package import... all in the interest of minimizing "surface area".</p>
<p>It's a tradeoff. Sure. I understand what he's getting at. I just don't fully agree.</p>
<p>We both agree though that's it's better to move up the error hierarchy; away from manipulating Error(). I'm happy with that.</p>
<p>EDIT:</p>
<p>It should be noted that these concerns could be solved if Go allowed importing specific pieces of a package, e.g., <code>import net/http.ProtocolError</code>, or what have you. That way, you get the best of both worlds. Also, note that behavioral and type errors play well with each other, it's not necessarily an either/or decision.</p></pre>dobegor: <pre><p>You can't type-cast to determine the error. You'll need to do smelly strings.Contains on error string and etc.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传