Посмотрите на тип RawMessage
в пакете encoding/json
. Это позволяет отложить декодирование значений JSON на потом. Например:
Results []json.RawMessage `json:"results"`
или даже ...
Results json.RawMessage `json:"results"`
Поскольку json.RawMessage
- это просто кусочек байтов, это будет намного эффективнее, чем промежуточный []interface{}
, который вы отменяете.
Что касается второй части о том, как собрать их в один фрагмент с учетом нескольких чтений страниц, вы можете задать этот вопрос вызывающему, заставив вызывающего использовать тип фрагмента.
// Then in a method requesting all results for a single entity
var entityPages [][]Entity1
client.ListRequestAll("https://foo.bar/entities1.json", &entityPages)
Это все еще имеет проблему неограниченного потребления памяти, которую имеет ваш общий дизайн, так как вам нужно загрузить все страницы / элементы одновременно. Возможно, вы захотите перейти на абстракцию Open / Read, например, работать с файлами. У вас есть какой-нибудь метод Open
, который возвращает другой тип, который, например, os.File
, предоставляет метод для чтения подмножества данных за один раз, при этом внутренний запрос страниц и буферизация по мере необходимости.
Возможно, что-то вроде этого (не проверено):
type PagedReader struct {
c *Client
buffer []json.RawMessage
next string
}
func (r *PagedReader) getPage() {
f := r.c.ListRequest(r.next)
r.next = f.Data.Next
r.buffer = append(r.buffer, f.Data.Results...)
}
func (r *PagedReader) ReadItems(output []interface{}) int {
for len(output) > len(buffer) && r.next != "" {
r.getPage()
}
n := 0
for i:=0;i<len(output)&&i< len(r.buffer);i++ {
json.Unmarshal(r.buffer[i], output[i] )
n++
}
r.buffer = r.buffer[n:]
return n
}