Пустой указатель при обращении к фрагменту или карте, возвращенной функцией - PullRequest
0 голосов
/ 11 июня 2018

Обычно это будет что-то вроде этого

func main() {
   my_map := myFunc()
   fmt.Println(my_map)
}

func myFunc() map[string]interface{} {
   // .... create a map....
   return map
}

, когда я запускаю такие шаблоны, у меня почти всегда возникает ошибка, когда я пытаюсь распечатать my_map.

Это также происходит, если я возвращаю []byte тип.

Теперь вот что: я думаю, понимаю, почему возвращение []byte, созданного внутри myFunc(), приведет к segfaultпри печати в main: срез ссылается на массив, который был создан внутри myFunc, поэтому, как только myFunc вернется, этот массив будет удален сборщиком мусора и, следовательно, segfault.

I 'Я собираюсь предположить, что нечто подобное происходит с картой.

В C ++ это просто создаст копию карты и вернет это -> без проблем.То же самое, если я вернул массив.

Почему в go я не могу просто вернуть созданную карту и каков наилучший способ вернуть карту (созданную внутри функции), не приводя к segfaultкак только эта функция вернется в main?

func twitterRequest(query string, token string) map[string]interface{} {
    req, err := http.NewRequest("GET", query, nil)
    if err != nil {
        log.Fatal(err.Error())
    }
    req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
    client := &http.Client{}
    resp, err2 := client.Do(req)
    if err2 != nil {
        log.Fatal(err.Error())
    }
    defer resp.Body.Close()
    respBody, _ := ioutil.ReadAll(resp.Body)
    var jsonResp interface{} // turns into map[string]interface{}
    err = json.Unmarshal(respBody, &jsonResp)
    if err != nil {
        log.Fatal("wrong")
    }
    return jsonResp.(map[string]interface{})
}

func searchTweets(queries string, token string) {
    builder := strings.Builder{}
    builder.WriteString(tweetSearchUrl)
    builder.WriteString("q=")
    builder.WriteString(queries)
    queryUrl := url.QueryEscape(builder.String())
    map1 := twitterRequest(queryUrl, token)
    fmt.Println(map1) // SEG FAULT HERE
}

1 Ответ

0 голосов
/ 11 июня 2018

Возвращение значений, созданных внутри функции в Go, вполне нормально и обычно используется.Компилятор использует escape-анализ, и если он не может доказать, что значение не выходит из функции, оно будет размещено в куче, и поэтому не будет уничтожено, когда функция вернется, и может быть использовано после того, как функция вернулась.

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

Скорее всего, ошибка в вашей функции twitterRequest(), возможно, когда вы делаете утверждение типа, возвращающее значение:

return jsonResp.(map[string]interface{})

Это утверждение типа приводит к панике во время выполнения, если jsonResp равно nil или значение, которое оно содержит, не относится к типу map[string]interface{}.Это может быть nil, если тело ответа является недействительным JSON, и это может быть значение другого типа, если тело ответа является допустимым JSON, но это, например, массив JSON.

Сначала проверьте всеошибки, в том числе при чтении тела:

respBody, _ := ioutil.ReadAll(resp.Body)

Сделайте это следующим образом:

respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
    // Handle error, optionally return
}

Вам также следует использовать специальную форму утверждения типа:

m, ok := jsonResp.(map[string]interface{})
if !ok {
    // jsonResp is nil or is not a map!
    // Handle this error case and return
}

return m // all ok

Эта специальная форма утверждения типа никогда не будет паниковать, вместо этого, если утверждение не выполняется, переменная ok будет иметь значение false, что вы можете проверить и обработать правильно.Если ok равно true, это означает, что jsonResp не было nil, и значение внутри него действительно было значением типа map[string]interface{}, которое хранится в m, которое вы можете безопасно вернуть.

...