【问题标题】:Return error from the channel从通道返回错误
【发布时间】:2014-08-05 14:57:21
【问题描述】:

当我在 Go 中编写一个函数时,它应该返回一个值和一个类似的错误

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

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

【问题讨论】:

    标签: go


    【解决方案1】:

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

    type Result struct {
        Message string
        Error error
    }
    
    ch := make(chan Result)
    

    【讨论】:

    • 我在这里传递一个引用类型对吗?我在某处读过,当可以避免通过通道传递引用类型时,这是真的吗?
    • 不正确,你的意思是指针吗?没有“引用类型”的官方概念,但切片和映射通常称为“引用类型”。您可以通过通道传递任何您想要的内容,其语义与任何其他调用或赋值相同。
    • Go 的流行语是“不要通过共享内存进行通信;而是通过通信来共享内存”。通道为您提供了一种在线程之间进行通信的方式,而无需防止同时访问相同的内存。所以你可以共享一个指针,但是(如果我理解正确的话)这样做意味着你不会有两个或多个线程同时访问该内存。一个线程可以接收一个指针,在它指向的内存上工作,然后停止工作并通过通道传递那个指针。在任何给定时间只有一个线程处理该指针。
    【解决方案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 配合使用。

        【讨论】:

          猜你喜欢
          • 2014-10-01
          • 1970-01-01
          • 2019-02-05
          • 2015-09-04
          • 2020-06-09
          • 1970-01-01
          • 2019-03-02
          • 1970-01-01
          • 2017-04-15
          相关资源
          最近更新 更多