【问题标题】:"Invalid memory address" in Golang using ioutil.ReadAll()Golang 中使用 ioutil.ReadAll() 的“无效内存地址”
【发布时间】:2018-12-27 03:11:11
【问题描述】:

我目前正在学习 Golang(到目前为止我很喜欢它)。但不幸的是,我被困了几个小时,似乎在 Google 上找不到任何解决问题的方法。

所以这是我的问题。我有这段代码(来自教程):

func main() {
    var s SitemapIndex

    resp, _ := http.Get("https://www.washingtonpost.com/news-sitemaps/index.xml")
    bytes, _ := ioutil.ReadAll(resp.Body)
    resp.Body.Close()

    xml.Unmarshal(bytes, &s)

    for _, Location := range s.Locations {
        resp, _ := http.Get(Location)
        ioutil.ReadAll(resp.Body)

    }

}

我知道,我的代码不完整,但那是因为我删除了不会导致问题的部分,使其在 Stackoverflow 上更具可读性。

所以当我得到Location 的内容并尝试使用ioutil.ReadAll() 处理数据时,我收到这个错误提示:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x1210a69]

goroutine 1 [running]:
main.main()
    /Users/tom/Developer/Go/src/news/index.go:23 +0x159
exit status 2

我真的不明白这个错误,不管我怎么看。我试图通过执行_, e := ioutil.ReadAll(resp.Body) 然后打印e 来从ioutil.ReadAll(resp.Body) 中提取错误,但是这样做会引发另一个 错误...

我在某处读到可能是因为返回给我的正文有错误,但在教程中它运行良好。

希望你们能给我一个解决方案。谢谢。

编辑:这是我定义的结构:

type SitemapIndex struct {
    Locations []string `xml:"sitemap>loc"`
}

type News struct {
    Titles []string `xml:"url>news>title"`
    Keywords []string `xml:"url>news>keywords"`
    Locations []string `xml:"url>loc"`
}

type NewsMap struct {
    Keyword string
    Location string
}

【问题讨论】:

  • 可以复制 SitemapIndex 来查看吗?
  • 谢谢,我刚刚编辑了帖子
  • 你忽略了错误,这样没人能发现问题。而不是丢弃错误处理它们。像这样。 resp,er := http.Get("your address");if err!= nil { log.Fataln(err) }

标签: http pointers go


【解决方案1】:

围棋的第一条规则:检查错误。


当函数调用返回错误时,它是调用者的 有责任对其进行检查并采取适当的措施。

通常当一个函数返回一个非零错误时,它的其他结果是 未定义,应该被忽略。

The Go Programming Language, Alan A. A. Donovan and Brian W. Kernighan


例如,

if err != nil {
    fmt.Printf("%q\n", Location) // debug error
    fmt.Println(resp)            // debug error
    fmt.Println(err)
    return
}

输出:

"\nhttps://www.washingtonpost.com/news-sitemaps/politics.xml\n"
<nil>
parse 
https://www.washingtonpost.com/news-sitemaps/politics.xml
: first path segment in URL cannot contain colon

如果你没有发现这个错误并继续使用resp == nil 那么

bytes, err := ioutil.ReadAll(resp.Body)

输出:

panic: runtime error: invalid memory address or nil pointer dereference

package main

import (
    "encoding/xml"
    "fmt"
    "io/ioutil"
    "net/http"
    "strings"
)

type SitemapIndex struct {
    Locations []string `xml:"sitemap>loc"`
}

func main() {
    var s SitemapIndex

    resp, err := http.Get("https://www.washingtonpost.com/news-sitemaps/index.xml")
    if err != nil {
        fmt.Println(err)
        return
    }
    bytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    err = resp.Body.Close()
    if err != nil {
        fmt.Println(err)
        return
    }

    err = xml.Unmarshal(bytes, &s)
    if err != nil {
        fmt.Println(err)
        return
    }

    for _, Location := range s.Locations {
        resp, err := http.Get(Location)
        if err != nil {
            fmt.Printf("%q\n", Location) // debug error
            fmt.Println(resp)            // debug error
            fmt.Println(err)
            return
        }
        bytes, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(len(bytes))
        err = resp.Body.Close()
        if err != nil {
            fmt.Println(err)
            return
        }
    }
}

【讨论】:

    【解决方案2】:

    好的,所以我找到了问题的原因以及解决方法。问题是 url 有一些我没有看到的换行符。

    所以不要这样做:

    resp, err := http.Get(Location)
    

    我这样做了:

    resp, err := http.Get(strings.TrimSpace(Location))
    

    解决了。

    【讨论】:

      【解决方案3】:

      正如 Mostafa 提到的,您必须正确处理错误。 golang中没有try catch。 像这样的事情我已经累了。 至少它捕获了 liteIde 中的 url 错误

      package main
      
      import (
          "encoding/xml"
          "fmt"
          "io/ioutil"
          "net/http"
          "os"
          "runtime"
      )
      
      type SitemapIndex struct {
          Locations []string `xml:"sitemap>loc"`
      }
      
      func main() {
          var s SitemapIndex
      
          resp, err := http.Get("https://www.washingtonpost.com/news-sitemaps/index.xml")
          if err != nil {
              fmt.Println("Unable to get the url ")
              os.Exit(1)
          }
          bytes, _ := ioutil.ReadAll(resp.Body)
          defer resp.Body.Close()
          //fmt.Println(string(bytes))
          xml.Unmarshal(bytes, &s)
          //fmt.Println(len(s.Locations))
      
          for _, Location := range s.Locations {
              //fmt.Println(Location)
              go func() {
                  r, err := http.Get(Location)
                  if err != nil {
                      fmt.Println("Error occured ", err)
                      return
                  }
                  bytes, err := ioutil.ReadAll(resp.Body)
                  if err != nil {
                      fmt.Printf("Error in reading :", err)
                  }
                  fmt.Println(string(bytes))
                  r.Body.Close()
              }()
          }
          runtime.Gosched()
      }
      

      【讨论】:

      • 感谢您的回答。所以我按照要求打印了错误,上面写着first path segment in URL cannot contain colon。回复是&lt;nil&gt;顺便说一句。你知道为什么吗?
      • 我用 goroutine 编写了测试代码,但你可能不得不在没有 goroutine 的情况下尝试它。调试打印中的每个字符以查看是否在位置 url 中添加了任何其他字符。
      • 该错误表示 URL 有问题需要查看。我们如何缓冲或搅拌,需要确保它除了 url 本身没有任何其他字符
      • 我试过了,最后加了runtime.Gosched(),但是没有解决问题。顺便说一句,这条线有什么作用?
      • 好的,我的建议是,查看范围循环中的 URL(位置 url)并检查它是否添加了任何额外的引号或其他内容。 runtime.Goshed() 调用确保主程序在所有 goroutine 完成之前不会退出
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-15
      • 2023-01-23
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多