Go语言 我如何编写一个函数,它接受两个函数(返回结构体)并同时运行它们?

omqzjyyz  于 2023-01-06  发布在  Go
关注(0)|答案(1)|浏览(116)

在我正在编写的golang包中,我经常需要发出2个HTTP请求来获取所需的数据。
我的包包含客户端函数,这些函数通常没有参数,返回一个结构和一个错误。
第一个月
然而,我希望能够编写一个泛型函数,它可以接受其中两个客户端函数作为参数,并发地运行它们,并简单地返回填充了来自API的数据的结构体。
理想情况下,我希望函数调用如下所示:

struct1, struct2, err := rrunFunctions(client.GetProduct, client.GetSizes)

到目前为止,我已经编写了以下泛型函数:https://go.dev/play/p/IA8LJqY0FPe
问题是,由于GetProductGetSizes都返回structerror,而不是interface{}error,因此我在编译时得到以下错误:

./prog.go:54:28: cannot use client.GetProduct (value of type func() (*Product, error)) as type func() (interface{}, error) in argument to runFunctions
./prog.go:54:47: cannot use client.GetSizes (value of type func() (*Sizes, error)) as type func() (interface{}, error) in argument to runFunctions

我的问题是如何克服这一点?在go中编写这样的泛型函数是可能的吗?
任何关于以这种方式使用并发的一般提示也将受到欢迎。

t9eec4r0

t9eec4r01#

是的,使用泛型是可能的。为函数的2个返回类型使用2个类型参数:

func runFunctions[T1, T2 any](
    f1 func() (T1, error),
    f2 func() (T2, error),
) (res1 T1, res2 T2, err error) {
    var wg sync.WaitGroup
    wg.Add(2)

    var err1, err2 error

    go func() {
        defer wg.Done()
        res1, err1 = f1()
    }()

    go func() {
        defer wg.Done()
        res2, err2 = f2()
    }()

    wg.Wait()

    // check errors
    if err1 != nil {
        err = err1
        return
    }
    if err2 != nil {
        err = err2
        return
    }

    return
}

注:

  • 使用defer调用wg.Done()
  • 必须检查wg.Wait()之后的错误!

使用它也变得更简单,因为你不必处理类型Assert:

func main() {
    defer timeTrack(time.Now(), "Fetching products with sizes")
    fmt.Println("Starting synchronous calls...")

    client := &Client{}

    prodModel, sizesModel, err := runFunctions(client.GetProduct, client.GetSizes)
    if err != nil {
        // return error
    }

    build(prodModel, sizesModel)
}

这将输出(在Go Playground上尝试):

Starting synchronous calls...
product 123 has size S
product 123 has size M
product 123 has size L
2009/11/10 23:00:05 Fetching products with sizes took 5s

相关问题