You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Go语言中API请求相关函数的代码重复?

用泛型实现通用并发请求函数,消除代码重复

针对你遇到的并发请求函数逻辑重复、缺少自定义结构体支持的问题,用Go泛型可以完美解决——实现一个通用的底层并发请求函数,让所有特定类型的并发请求都基于它封装,彻底消除重复代码,同时轻松扩展自定义结构体的支持。

第一步:定义通用并发请求底层函数

这个函数接收请求输入列表和单个请求的处理函数,利用泛型T适配任意返回类型,通过通道保证结果顺序和并发安全:

import "sync"

// GenericConcurrentRequests 通用并发请求处理函数
// 参数:
//   inputs: 请求输入列表(可以是URL字符串,也可以是自定义的http.Request对象等)
//   singleReqFunc: 单个请求的处理函数,接收单个输入,返回泛型结果T和错误
// 返回:按输入顺序排列的结果切片、对应位置的错误切片
func GenericConcurrentRequests[T any, I any](inputs []I, singleReqFunc func(I) (T, error)) ([]T, []error) {
    resultChan := make(chan struct {
        idx   int
        value T
        err   error
    }, len(inputs))

    var wg sync.WaitGroup
    wg.Add(len(inputs))

    // 启动goroutine处理每个请求
    for i, input := range inputs {
        go func(idx int, in I) {
            defer wg.Done()
            val, err := singleReqFunc(in)
            resultChan <- struct {
                idx   int
                value T
                err   error
            }{idx, val, err}
        }(i, input)
    }

    // 所有请求完成后关闭通道
    go func() {
        wg.Wait()
        close(resultChan)
    }()

    // 初始化结果容器,按原顺序填充
    results := make([]T, len(inputs))
    errs := make([]error, len(inputs))
    for res := range resultChan {
        results[res.idx] = res.value
        errs[res.idx] = res.err
    }

    return results, errs
}

第二步:基于通用函数封装特定类型的并发请求

原来的GetJsonAsMapMultiple、GetJsonAsMapArrayMultiple,以及新增的自定义结构体并发请求,都可以一行代码实现:

假设你已有以下单请求函数:

// 单请求返回Map
func GetJsonAsMap(url string) (map[string]interface{}, error) {
    // 原有的单请求逻辑:发送请求、解析JSON为Map
}

// 单请求返回Map数组
func GetJsonAsMapArray(url string) ([]map[string]interface{}, error) {
    // 原有的单请求逻辑:发送请求、解析JSON为Map数组
}

// 单请求填充自定义结构体
func GetJsonAsStruct[T any](url string) (T, error) {
    // 原有的单请求逻辑:发送请求、解析JSON为自定义结构体
}

现在封装并发版本:

// Map类型的并发请求
func GetJsonAsMapMultiple(urls []string) ([]map[string]interface{}, []error) {
    return GenericConcurrentRequests[map[string]interface{}, string](urls, GetJsonAsMap)
}

// Map数组类型的并发请求
func GetJsonAsMapArrayMultiple(urls []string) ([][]map[string]interface{}, []error) {
    return GenericConcurrentRequests[[]map[string]interface{}, string](urls, GetJsonAsMapArray)
}

// 自定义结构体的并发请求
func GetJsonAsStructMultiple[T any](urls []string) ([]T, []error) {
    return GenericConcurrentRequests[T, string](urls, GetJsonAsStruct[T])
}

扩展支持自定义请求(如带Header/Body的HTTP请求)

如果需要支持更复杂的自定义请求(比如带请求头、请求体的http.Request),只需要调整输入类型即可:

// 单请求处理自定义http.Request,返回结构体
func GetJsonAsStructWithRequest[T any](req *http.Request) (T, error) {
    // 原有的单请求逻辑:发送自定义请求、解析JSON为结构体
}

// 自定义请求的并发版本
func GetJsonAsStructWithRequestMultiple[T any](requests []*http.Request) ([]T, []error) {
    return GenericConcurrentRequests[T, *http.Request](requests, GetJsonAsStructWithRequest[T])
}

方案优势

  1. 彻底消除代码重复:所有并发请求的核心逻辑(goroutine管理、结果收集、顺序保证)都集中在GenericConcurrentRequests中,上层只需关注单请求的业务逻辑。
  2. 灵活扩展:新增任何类型的并发请求,只需封装一行代码,无需重复编写并发逻辑。
  3. 统一维护:后续如果需要添加超时控制、重试机制、请求限流等功能,只需修改通用函数一处即可,所有上层函数自动受益。

内容的提问来源于stack exchange,提问作者vipaware

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:02:07