Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return error from the channel

Tags:

go

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?

like image 285
softshipper Avatar asked Aug 05 '14 14:08

softshipper


People also ask

How do I return a Goroutine error?

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.

What is a Goroutine?

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.

How do you wait for a Goroutine to finish?

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.

How do I close a channel in Golang?

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.


3 Answers

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)
like image 149
JimB Avatar answered Oct 11 '22 00:10

JimB


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)
}
like image 28
Ian Davis Avatar answered Oct 11 '22 01:10

Ian Davis


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)
}
like image 11
AndreKR Avatar answered Oct 11 '22 00:10

AndreKR