Ошибка возврата из канала

Когда я пишу функцию в Go, она должна вернуть значение и ошибку, например

func createHashedPassword(password string) string, error {
    //code
}

Я хочу выполнить это createHashedPassword в goroutine, и я думаю, чтобы передавать данные через канал.
Но мой вопрос: как я могу обрабатывать ошибку здесь или в goroutine?

Ответ 1

Обычно для объединения нескольких выходов в структуру и возврата их вместе по одному каналу.

type Result struct {
    Message string
    Error error
}

ch := make(chan Result)

Ответ 2

Вы можете передать канал ошибки, а также канал результата.

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)
}

Ответ 3

Вот мои два предпочтительных способа:

Два канала, завернутые

Это способ "двух каналов", но заключенный в функцию, чтобы он выглядел аналогично общему шаблону:

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
}

И называется так:

resultCh, errorCh := createHashedPasswordAsynchronously("mysecret")
select {
case result := <-resultCh:
    storeHashedPassword(result)
case err := <-errorCh:
    log.Println(err.Error())
}

Анонимная структура

Это способ "анонимной структуры", похожий на ответ @saward, но без явного указания членов структуры:

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)
}

Ответ 4

(так как я еще не могу прокомментировать...)

Я повторяю, что сказал JimB:

type Result struct {
    Message string
    Error error
}

ch := make(chan Result)

Проблема с двумя отдельными каналами, одна для результата и другая для ошибки, заключается в том, что (как я понимаю) он не будет поддерживать параллельные потоки из коробки.

Можно, например, иметь два потока, отправляющих данные одновременно, где ответы выходят из строя. То есть, сначала вы получаете результат из потока 1, но сначала ошибку из потока 2.

Легко создавать новые типы, такие как JimB, и хорошо работать с goroutines.