<p>Hey! I'm fairly new to golang, and I'm a bit confused on an elegant way to do the following in golang.</p>
<p>I want to create a function that is optionally a goroutine, but I want it to be able to return errors. The initial way I tried to solve this problem was an error channel. </p>
<pre><code>func optionalRoutine(stuff int, errChan chan<- error){
defer close(errChan)
// do stuff
errChan <- err
}
</code></pre>
<p>But, this leads to a deadlock if not run in a goroutine because there err is waiting to send.</p>
<pre><code>go optionalRoutine(0, errChan) // works
optionalRoutine(0, errChan) // doesn't work
</code></pre>
<p>So, I think anything to do with channels is out of the question. I could pass in a pointer to an error that gets set by the function if there is an error, but I don't really understand how to detect if the function is done. I could use the sync package's waitgroup, but I don't know if there is a better solution.</p>
<p>Thanks in advance for the help!</p>
<hr/>**评论:**<br/><br/>binaryblade: <pre><p>Have it just return the error for when you want to call it directly. Then when you need a go routine just wrap it in a lambda that handles the channel stuff.</p></pre>intermernet: <pre><p>Quick example:</p>
<pre><code>package main
import "fmt"
func f() (int, error) {
return 1, fmt.Errorf("This is an error")
}
func main() {
// As a normal function
i, err := f()
fmt.Println(i, err)
// As a goroutine
ic := make(chan int)
ec := make(chan error)
go func() {
i, err := f()
ic <- i
ec <- err
}()
fmt.Println(<-ic, <-ec)
}
</code></pre>
<p><a href="http://play.golang.org/p/BO_qF2qELh" rel="nofollow">playground</a></p></pre>earthboundkid: <pre><p>Your example requires the answer channel to send before the error channel can. I'd probably change it a little so you can receive in any order. Or maybe don't send a value if the error is non-nil. </p></pre>intermernet: <pre><p>True, it would be better to only send the error if it was non-nil, then have a select statement to receive.</p></pre>earthboundkid: <pre><p>Right, or send a struct that acts a value, error type.</p>
<p><a href="http://play.golang.org/p/OcV6ROurjk" rel="nofollow">http://play.golang.org/p/OcV6ROurjk</a></p></pre>tv64738: <pre><p>Rule of thumb: Write synchronous APIs, let the caller be in charge of concurrency.</p>
<p>You can use concurrency inside the API, but don't expose details in the API unnecessarily. (Necessary exception: when you know caller will want to integrate the call into a <code>select{}</code>.)</p></pre>lespritd: <pre><p>The easiest thing to do is to use your code you have but instantiate the channel with a size of 1</p>
<p><a href="http://play.golang.org/p/cBDXtett8N" rel="nofollow">http://play.golang.org/p/cBDXtett8N</a></p></pre>atishpatel2012: <pre><p>This solution seems to be the best in my opinion. And, I can check for the capacity of the errchan to ensure one with size 1 is passed in. Thank you again!</p></pre>egonelbre: <pre><p>Create the code as:</p>
<pre><code> func doStuff(stuff int) error {
</code></pre></pre>FiveRoundsRapid: <pre><p>Many sensible suggestions here. You could also have it accept a channel as an argument, but pass nil to it when not a goroutine, e.g.:</p>
<pre><code>func optionalRoutine(errChan chan error) error {
// do stuff
if errChan != nil {
errChan <- err
}
return err
}
func main() {
err1 := optionalRoutine(nil)
errChan := make(chan error)
go optionalRoutine(errChan)
err2 := <- errChan
}
</code></pre></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传