When i write a function in Go, it should return a value and an error like
func createHashedPassword(password string) string, error {
//code
}
I want to execute this createHashedPassword in a goroutine and I think to pass data via channel.
But my question is, how can I handle error here or in the goroutine?
Using a channel to return something is the only way you can guarantee to collect all return values from goroutines without overwriting them. There are multiple ways we can use the same return channels: We can use the return channel to indicate only the error. We can use it to return both the result and the error.
A goroutine is a lightweight thread managed by the Go runtime. go f(x, y, z) starts a new goroutine running f(x, y, z) The evaluation of f , x , y , and z happens in the current goroutine and the execution of f happens in the new goroutine.
The WaitGroup type of sync package, is used to wait for the program to finish all goroutines launched from the main function. It uses a counter that specifies the number of goroutines, and Wait blocks the execution of the program until the WaitGroup counter is zero.
We can close a channel in Golang with the help of the close() function. Once a channel is closed, we can't send data to it, though we can still read data from it. A closed channel denotes a case where we want to show that the work has been done on this channel, and there's no need for it to be open.
It's common to bundle multiple outputs into a struct, and return them together over a single channel.
type Result struct {
Message string
Error error
}
ch := make(chan Result)
You can pass in an error channel as well as a result channel.
errors := make(chan error, 0)
results := make(chan string, 0)
password := "test"
go func() {
result, err := createHashedPassword(string password)
if err != nil {
errors <- err
return
}
results <- result
}()
// do something else
// When you are ready to read from goroutine do this:
select {
case err := <- errors:
println(err)
case res := <- results:
println(res)
}
Here are my two preferred ways:
Two channels, wrapped
This is the "two channels" way, but wrapped into a function to make it look similar to the common pattern:
func createHashedPasswordAsynchronously(password string) (chan string, chan error) {
resultCh := make(chan string)
errorCh := make(chan error)
go func(password string) {
//code
if err != nil {
errorCh <- errors.New("Does not compute")
} else {
resultCh <- "8badf00d"
}
}(password)
return resultCh, errorCh
}
And called like this:
resultCh, errorCh := createHashedPasswordAsynchronously("mysecret")
select {
case result := <-resultCh:
storeHashedPassword(result)
case err := <-errorCh:
log.Println(err.Error())
}
Anonymous struct
This is the "anonymous struct" way, similar to @saward's answer, but without naming the struct members explicitly:
go func(password string, ch chan struct {
string
error
}) {
//code
if err != nil {
ch <- struct {
string
error
}{"", errors.New("Does not compute")}
} else {
ch <- struct {
string
error
}{"8badf00d", nil}
}
}("mysecret", ch)
r := <-ch
if r.error != nil {
log.Println(r.error.Error())
} else {
storeHashedPassword(r.string)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With