Проблема накопления / добавления значений в массив с использованием рекурсии с Go - PullRequest
0 голосов
/ 20 ноября 2018

Прежде всего, это моя первая не фиктивная программа, использующая Go.Будем благодарны за любые рекомендации.

Описание кода:

Я хочу получить всю информацию из API, где эта информация разбита на страницы.Поэтому я хочу перебрать все страницы, чтобы получить всю информацию.

Это то, что я сделал до сих пор:

У меня есть эти две функции:

func request(requestData *RequestData) []*ProjectsResponse {

    client := &http.Client{
        Timeout: time.Second * 10,
    }

    projects := []*ProjectsResponse{}
    innerRequest(client, requestData.URL, projects)

    return projects
}

func innerRequest(client *http.Client, URL string, projects []*ProjectsResponse) {

    if URL == "" {
        return
    }

    req, err := http.NewRequest("GET", URL, nil)
    if err != nil {
        log.Printf("Request creation failed with error %s\n", err)
    }
    req.Header.Add("Private-Token", os.Getenv("API_KEY"))

    res, err := client.Do(req)
    log.Printf("Executing request: %s", req.URL)

    if err != nil {
        log.Printf("The HTTP request failed with error %s\n", err)
    }
    data, _ := ioutil.ReadAll(res.Body)
    var response ProjectsResponse
    err = json.Unmarshal(data, &response)

    if err != nil {
        log.Printf("Unmarshalling failed with error %s\n", err)
    }

    projects = append(projects, &response)
    pagingData := getPageInformation(res)
    innerRequest(client, pagingData.NextLink, projects)
}

Нежелательное поведение:

Значения в массиве projects []*ProjectsResponse добавляются на каждой итерации рекурсии, но когда рекурсия заканчивается, я получаю пустой список массивов.Итак, как-то после того, как innerRequests заканчивается, в переменной project внутри метода request я ничего не получаю.

Надеюсь, кто-нибудь и обнаружит мою ошибку.Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Я предполагаю, что все объекты вашего проекта ограничены функцией, поэтому они больше не существуют, когда функция заканчивается. Я не думаю, что вам нужно, чтобы ваши проекты существовали до того, как вы вызовете innerRequest, поэтому вам, вероятно, следует просто заставить этот метод возвращать проекты. Я думаю, что-то вроде этого должно работать ...

func innerRequest(client *http.Client, URL string) []*ProjectsResponse {

if URL == "" {
    return nil
}

//More code...

pagingData := getPageInformation(res)
return append([]*ProjectsResponse{&response}, innerRequest(client, pagingData.NextLink)...)
}
0 голосов
/ 20 ноября 2018

Путаница заключается в способе обработки slice в Go. Здесь - это подробное объяснение, но я буду сокращать его.

Распространенным заблуждением является то, что slice, который вы передаете, является ссылкой на slice что неверноФактическая переменная, с которой вы работаете при обработке слайса, называется заголовок слайса .Это простой struct с ссылкой на базовый массив под обложками и соответствует правилам Go 1011 * pass by value , то есть копируется при передаче вфункция.Таким образом, если он не будет возвращен, у вас не будет обновленного заголовка.

Возврат данных из рекурсии следует прямому шаблону.Вот основной пример.Я также включаю версию, которая не требует возврата, но работает со срезом как ссылка, которая изменит оригинал.(Примечание. Передача указателей слайсов обычно не считается идиоматическим движением)

Ссылка на игровую площадку: https://play.golang.org/p/v5XeYpH1VlF

// correct way to return from recursion
func addReturn(s []int) []int {
    if finalCondition(s) {
        return s
    }
    s = append(s, 1)
    return addReturn(s)
}

// using a reference
func addReference(s *[]int) {
    if finalCondition(*s) {
        return
    }
    *s = append(*s, 1)
    addReference(s)
}

// whatever terminates the recursion
func finalCondition(s []int) bool {
    if len(s) >= 10 {
        return true
    }
    return false
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...