Я реорганизовал некоторый код, в котором я делал запрос для разных типов (Книги, Авторы и т. Д. c), и обнаружил, что делаю много одинаковых шагов для выполнения запроса на разных машинах, поэтому я начал рефакторинг и с использованием замыкания.
Проблема в том, что запросы возвращают разные типы, поэтому как захватить эти данные, а затем вернуть их.
Я закончил потоковую передачу результатов в чан интерфейсов. Оттуда я захватываю их в интерфейсе [], прежде чем, наконец, маршалировать их в конечный фрагмент, например [] * model.Book или [] * model.Author.
То, что я придумал, работает, но он кажется неэффективным, особенно при переходе от канала к срезу интерфейсов к последнему срезу.
Есть ли лучший способ захватить данные из интерфейса chan {} в переменную ответа, переданную в функцию excuteQueries?
Вот базовый c fun c, который выполняет запрос и передает результаты в канал интерфейса, называемый выходом. У меня их около 8 для разных типов, поэтому chan имеет тип interface {}
fn := func(db Database, query string, output chan<- interface{}) {
response, err := db.Books(query)
// Convert the data and write to the channel
for _, n := range response {
output <- &model.Book{Book: n}
}
}
Эта функция передается другому фонду, который выполняет итерацию по всем базам данных и выполняет запрос. Передается fun c и фрагмент, который используется для захвата результатов, т.е.
var results []*model.Book
executeQueries(fn, &results)
В функции executeQueries, которая вызывает 'fn', я создаю выходной канал и получаю go обычное чтение из него в [] интерфейс {}. После закрытия канала мы маршалируем все результаты из interfaceSlice в ответ. например,
typedef QueryFN func(db Database, query string, output chan<- interface{})
func(fn QueryFN, response interface{}) {
output := make(chan interface{})
// interfaceSlice is used to drain the channel
var interfaceSlice []interface{}
done := make(chan bool) // done channel used to indicate when the processing of the output channel is complete
go func() {
for i := range output {
interfaceSlice = append(interfaceSlice, i)
}
done<-true
}()
for _, db := range databases {
// some wait group logic....
go fn(db, query, output)
}
wg.Wait()
close(output)
<-done
marshallResponse(interfaceSlice, response)
Здесь код маршалла определяет тип ответа, а затем выполняет итерацию по входному срезу, приводя элементы. Это не масштабируется, когда я добавляю больше типов, и кажется неэффективным для go от канала до среза и до ответа.
func marshallResponse(input []interface{}, response interface{}) {
switch res := response.(type) {
case *[]*model.Book:
*res = make([]*model.Book, len(input))
data := *res
for i := range input {
data[i] = input[i].(*model.Book)
}
case *[]*model.Author:
*res = make([]*model.Author, len(input))
data := *res
for i := range input {
data[i] = input[i].(*model.Author)
}
}