Как избежать утверждения динамического c в функциях-оболочках? - PullRequest
1 голос
/ 21 февраля 2020

В приведенном ниже примере упрощенного кода мы выполняем десятки различных вызовов API с использованием библиотеки Go от нашего поставщика.

Библиотека поставщика предоставляет нам определение тел вызовов API:

// body of api call A
type requestBodyA struct {
    aa string
    bb int32
}

// body of api call B
type requestBodyB struct {
    id string
}

И с функциями, которые выполняют вызовы для нас:

// fn performs api call A
func callCreateA(body requestBodyA) {
    fmt.Println("Value of body is: ", body)
    // makes api call using body requestBodyA
}

// fn performs api call B
func callCreateB(body requestBodyB) {
    fmt.Println("Value of body is: ", body)
    // makes another api call using body requestBodyB
}

Мы используем их для создания наших собственных функций CRUD, где мы читаем файлы конфигурации и выполняем вызовы создания / чтения / обновления / удаления:

func createA() {
    bodyA := requestBodyA{
        aa: "asdasfsd",
        bb: 15,
    }

    // api retry loop
    for i := 1; i <= 3; i++ {
        // do some pre-checks (generic)

        callCreateA(bodyA)

        // check for errors (generic)
        // check if error is recoverable (generic)
        // if not return error (generic)
        // if yes use the for loop and try the call again in 1,2,3,5,8,13, .. seconds (generic)
    }
}

func createB() {
    bodyB := requestBodyB{
        id: "someUniqueId",
    }
    for i := 1; i <= 3; i++ {
        // do some pre-checks (generic)

        callCreateB(bodyB)

        // check for errors (generic)
        // check if error is recoverable (generic)
        // if not return error (generic)
        // if yes use the for loop and try the call again in 1,2,3,5,8,13, .. seconds (generic)
    }
}

Как вы можете видеть в функциях createA, createB, мы повторяем много общего кода c (предварительные проверки, обработка ошибок, повтор l oop и многое другое) в каждом CRUD FN мы создаем. Поскольку мы имеем дело с более чем 30 ресурсами, каждый из которых имеет свою собственную функцию вызова API создания, чтения, обновления и уничтожения, мы копируем один и тот же код более 100 раз.

Я бы хотел переместить все c наполняет некоторый genericApiCaller () и присваивает ему тело вызова в виде одного параметра и имени или указатель на функцию вызова API в качестве второго параметра.

Проблема 1: callCreateA и callCreateB needs «тело» разных типов. Было бы намного проще, если бы они использовали интерфейс {}, но эти функции исходят из SDK производителя, и было бы неразумно изменять их (причины обновления и т. Д. c). Как динамически утверждать «body interface {}» genericApiCaller () для «body requestBodyA» или «body requestBodyB»? Утверждение времени выполнения невозможно в Go, но я не нашел подходящего решения для него.

Проблема 2: Как передать функции с различными типами параметров в качестве параметра для genericApiCaller ()?

https://play.golang.org/p/incf-NEaSJ3

1 Ответ

1 голос
/ 21 февраля 2020

Вы можете попытаться расширить типы поставщиков, чтобы использовать что-то вроде интерфейса CallCreate:

type myBodyA requestBodyA
func (b myBodyA) CallCreate() {
    callCreateA((requestBodyA)(b))
}

type myBodyB requestBodyB
func (b myBodyB) CallCreate() {
    callCreateB((requestBodyB)(b))
}

type CallCreate interface {
    CallCreate()
}

func main() {
    var ifs CallCreate
    ifs = myBodyA{
        aa: "aa",
        bb: 15,
    }
    for i := 1; i <= 3; i++ {
        ifs.CallCreate()
    }
    ifs = myBodyB{
        id: "someUniqueId",
    }
    for i := 1; i <= 3; i++ {
        ifs.CallCreate()
    }

Вы также можете использовать что-то вроде

func genericApiCall(api,body interface{}) {
    av := reflect.ValueOf(api)
    av.Call([]reflect.Value{reflect.ValueOf(body)})
}

func main() {
    bodyA := requestBodyA{
        aa: "asdasfsd",
        bb: 15,
    }
    genericApiCall(callCreateA,bodyA)
    bodyB := requestBodyB{
        id: "someUniqueId",
    }
    genericApiCall(callCreateB,bodyB)
}

Однако, на мой взгляд, второе не так элегантно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...