在Go语言中传递一个泛型变量函数作为参数

ntjbwcob  于 2023-01-18  发布在  Go
关注(0)|答案(1)|浏览(152)

我正在处理一个ETL类型的应用程序,我所做的大多数错误处理只是重试API请求,直到它们成功(它们偶尔会由于连接等原因而随机失败)。

for err != nil {
    a,b,err = myfunc(c, d, e)
}
return a, b

因此,基本上只是继续做这个函数,直到错误消失(我把睡眠和其他错误检查作为必要的,以及避免速率限制)。
我想做的是将其简化为一个函数,该函数接受任意函数,在其输出中查找错误类型(如果它有一个),并递归地运行它,直到err!=nil。我的问题是,尽管go似乎允许使用任何(interface{})作为输入,它在函数定义上不是可变变量,例如(type func(a int)(int,int,error))作为类型func(... any)[]any
我想知道这是否是不可能做到的去,如果是这样的任何建议,以绕过它/获得类似的功能更习惯。
尝试使用类似的代码进行测试,但编译器不喜欢它。

func main() {
    Deal(SometimesFail, 10)
}

func Deal(f func(...any) []any, inputs ...any) []any {
    outputs := f(inputs)
    for _, val := range outputs {
        err, ok := val.(error)
        if ok {
            for err != nil {
                outputs = Deal(f, inputs...)
            }
            return outputs
        }
        continue
    }
    return outputs
} 

func SometimesFail(a int) (int, int, error) {
    random := rand.Intn(a)
    if random%2 == 0 {
        return random, random, nil
    } else {
        return random, random, errors.New("error")
    }
}

我想我能做的就是为每个函数的输出/输入模式创建一个类型,并允许泛型函数接受其中的任何一个,这样可以在实现目标的同时将代码重复保持在最低限度。

qaxu7uf2

qaxu7uf21#

以下内容:func(any)func(any, any)func(...any)都是不同的类型,不能将一种类型赋给另一种类型,没有一个函数类型可以包含所有这些类型。
解决这个问题的一种方法是将函数调用(必须知道函数的确切类型)与重试逻辑解耦:

type result struct {
    vals []any
    err  error
}

func main() {
    vals := repeatUntilSuccess(func(inputs ...any) result {
        val, err := failingRandomly(10)
        return result{[]any{val}, err}
    })

    fmt.Println(vals)
}

func repeatUntilSuccess(fn func(...any) result) []any {
    res := fn()
    for res.err != nil {
        res = fn()
    }
    return res.vals
}

func failingRandomly(i int) (int, error) {
    random := rand.Intn(i)
    if random%2 == 0 {
        return random, nil
    } else {
        return random, errors.New("bad luck")
    }
}

相关问题