#go
#Вперед
Вопрос:
Все еще немного новичок в go. В качестве простого проекта я пытаюсь написать API-оболочку для API Kiva. Я пытаюсь избежать написания дублирующего кода для обработки выгружаемых ответов из API, но, учитывая отсутствие в Go универсальных типов, я не нашел способа сделать это и не уверен, возможно ли это.
Я пытался использовать переключатели типов и пакет reflect, чтобы избежать выполнения одного и того же в нескольких функциях, но безуспешно. Это текущая итерация моего (полностью нефункционального) кода:
type PagingData struct {
Total int `json: "total"`
Page int `json: "page"`
PageSize int `json: "page_size"`
Pages int `json: "pages"`
}
type PagedLoanResponse struct {
Paging PagingData `json: "paging"`
Items []Loan `json: "loans"`
}
type PagedLenderResponse struct {
Paging PagingData `json: "paging"`
Items []Lender `json: "lenders"`
}
func (c *Client) doPaged(method string, urlpath string, query url.Values, body io.Reader, v interface{}, numPages int) ([]interface{}, error) {
if numPages < 0 {
return nil, fmt.Errorf("less than zero is unacceptable")
}
pr := reflect.New(reflect.TypeOf(v))
if query == nil {
query = url.Values{}
}
// get the first page
err := c.do(method, urlpath, query, body, amp;pr)
if err != nil {
return nil, err
}
if pr.Paging.Pages == 1 {
return pr.Items, nil
}
if numPages == 0 {
numPages = pr.Paging.Pages
}
items := make(reflect.New(reflect.TypeOf(pr.Items)), 0, pr.Paging.Total)
items = append(items, pr.Items...)
for i := 2; i <= numPages; i {
query.Set("page", strconv.Itoa(i))
err := c.do("GET", urlpath, query, nil, amp;pr)
if err != nil {
return nil
}
items = append(items, pr.Items...)
}
return items, nil
}
func (c *Client) GetNewestLoans(numPages int) ([]Loan, error) {
baseURL := "/v1/loans/newest"
var p PagedLoanResponse
loans, nil := c.doPaged("GET", baseURL, nil, nil, p, numPages)
}
Ответ №1:
Единственное, что вы могли бы сделать, это иметь интерфейс для всего, что доступно для просмотра. Возможно, вызывается Pagable
:
type Pagable interface { Paging() PagingData }
и единственный тип, который его реализует:
type Pager struct {
Paging PagingData `json:"paging"`
}
func(p Pager) Paging() PagingData {
return p.Paging
}
Тогда ваши другие типы могут «встраивать» a Pager
для автоматической реализации Pagable
и включать эти поля:
type PagedLenderResponse struct {
Paging
Items []Lender `json: "lenders"`
}
Если doPaged
затем принимает Pagable
вместо interface{}
for v
, вы можете вызвать Paging()
его и получить содержимое страницы, а затем пакет json может записать остальное в ответ для вас. Нет interface{}
и отражение не требуется.
Комментарии:
1. Этот подход по-прежнему требует большего количества повторений, чем я надеялся, в каждой функции, вызывающей doPaged, чтобы удалить информацию о подкачке из ответов, но подход, который вы описываете, вероятно, настолько хорош, насколько я получу — спасибо!