Go语言 从通道返回错误

wi3ka0sx  于 2023-01-03  发布在  Go
关注(0)|答案(5)|浏览(135)

当我在Go语言中写一个函数时,它应该返回一个值和一个如下的错误

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

我想在一个goroutine中执行这个createHashedPassword,我想通过通道传递数据。
但我的问题是,我该如何处理这里或goroutine中的错误呢?

s6fujrry

s6fujrry1#

通常将多个输出捆绑到一个结构体中,并通过单个通道将它们一起返回。

type Result struct {
    Message string
    Error error
}

ch := make(chan Result)
s8vozzvw

s8vozzvw2#

可以传入错误通道和结果通道。

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

fd3cxomn3#

以下是我的两种首选方法:

两个声道,环绕

这是“两个通道”的方式,但 Package 成一个函数,使其看起来类似于常见模式:

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

omhiaaxx4#

(因为我还不能发表评论...)
我附和JimB的话:

type Result struct {
    Message string
    Error error
}

ch := make(chan Result)

两个独立通道(一个用于结果,另一个用于错误)的问题在于(据我所知)它不支持开箱即用的并发线程。
例如,您可能有两个线程同时发送数据,但回复的顺序不对,也就是说,您首先从线程1接收结果,但首先从线程2接收错误。
像JimB建议的那样创建新类型很容易,而且应该可以很好地与goroutine一起工作。

b5lpy0ml

b5lpy0ml5#

常见模式之一是将错误通道和结果通道传递给函数:

package main

import (
  "fmt"
)

func main() {
  password := "blah blah"
  resultChan := make(chan string)
  errChan := make(chan error)

  go createHashedPassword(password, resultChan, errChan)

  // Do some other stuff

  select {
  case err := <-errChan:
    fmt.Println(err)
  case res := <-resultChan:
    fmt.Println(res)
  }
}

func createHashedPassword(password string, resultChan chan string, errChan chan error) {
  // your code for hashing and stuff
  if err != nil {
    errChan <- err
    return
  }
  resultChan <- result
}

您还可以在createHashedPassword内部创建通道,如AndreKR所述,
或者在匿名goroutine中调用createHashedPassword,就像Ian Davis所说的那样。
还有一些其他可能的模式,您可以合并combined struct组合其中的任何一种模式:

type Result struct {
  err error
  msg string
}

type Result struct {
  err error
  msg *string // in cases that empty string can be a true result, you can evaluate msg with nil
}

我还应该提到,在某些特殊情况下,我们不返回错误,而只是将其记录在那里。

package main

import (
    "fmt"
    "log"
)

func main() {
    password := "blah blah"
    resultChan := make(chan string)

    go createHashedPassword(password, resultChan)

    // Do some other stuff

    fmt.Println(<-resultChan) // Be careful that it's a blocking code.
}

func createHashedPassword(password string, resultChan chan string) {
    // your code for hashing and stuff
    if err != nil {
        log.Println(err) // *** Here we just log the error, or handle it.
    }
    resultChan <- result
}

相关问题