转到: 慌乱: 运行时错误: 无效的内存地址或取消引用空指针

当运行我的围棋程序时,它会感到恐慌并返回以下结果:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x38 pc=0x26df]


goroutine 1 [running]:
main.getBody(0x1cdcd4, 0xf800000004, 0x1f2b44, 0x23, 0xf84005c800, ...)
/Users/matt/Dropbox/code/go/scripts/cron/fido.go:65 +0x2bb
main.getToken(0xf84005c7e0, 0x10)
/Users/matt/Dropbox/code/go/scripts/cron/fido.go:140 +0x156
main.main()
/Users/matt/Dropbox/code/go/scripts/cron/fido.go:178 +0x61


goroutine 2 [syscall]:
created by runtime.main
/usr/local/Cellar/go/1.0.3/src/pkg/runtime/proc.c:221


goroutine 3 [syscall]:
syscall.Syscall6()
/usr/local/Cellar/go/1.0.3/src/pkg/syscall/asm_darwin_amd64.s:38 +0x5
syscall.kevent(0x6, 0x0, 0x0, 0xf840085188, 0xa, ...)
/usr/local/Cellar/go/1.0.3/src/pkg/syscall/zsyscall_darwin_amd64.go:199 +0x88
syscall.Kevent(0xf800000006, 0x0, 0x0, 0xf840085188, 0xa0000000a, ...)
/usr/local/Cellar/go/1.0.3/src/pkg/syscall/syscall_bsd.go:546 +0xa4
net.(*pollster).WaitFD(0xf840085180, 0xf840059040, 0x0, 0x0, 0x0, ...)
/usr/local/Cellar/go/1.0.3/src/pkg/net/fd_darwin.go:96 +0x185
net.(*pollServer).Run(0xf840059040, 0x0)
/usr/local/Cellar/go/1.0.3/src/pkg/net/fd.go:236 +0xe4
created by net.newPollServer
/usr/local/Cellar/go/1.0.3/src/pkg/net/newpollserver.go:35 +0x382

我看过其他人对相同异常的反应,但是看不到任何简单的东西(比如一个未处理的错误)。

我在一台没有访问代码中列出的 API 服务器的机器上运行它,但是我希望它会返回一个适当的错误(因为我曾试图捕捉这类错误)。

package main


/*
Fido fetches the list of public images from the Glance server, captures the IDs of images with 'status': 'active' and then queues the images for pre-fetching with the Glance CLI utility `glance-cache-manage`. Once the images are added to the queue, `glance-cache-prefetcher` is called to actively fetch the queued images into the local compute nodes' image cache.


See http://docs.openstack.org/developer/glance/cache.html for further details on the Glance image cache.
*/


import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
/*
"log"
"log/syslog"
*/
"net/http"
"os"
"os/exec"
)


func prefetchImages() error {


cmd := exec.Command("glance-cache-prefetcher")
err := cmd.Run()


if err != nil {
return fmt.Errorf("glance-cache-prefetcher failed to execute properly: %v", err)
}


return nil
}


func queueImages(hostname string, imageList []string) error {


for _, image := range imageList {
cmd := exec.Command("glance-cache-manage", "--host=", hostname, "queue-image", image)
err := cmd.Run()


if err != nil {
return fmt.Errorf("glance-cache-manage failed to execute properly: %v", err)
} else {
fmt.Printf("Image %s queued", image)
}
}


return nil
}


func getBody(method string, url string, headers map[string]string, body []byte) ([]byte, error) {


client := &http.Client{}
req, err := http.NewRequest(method, url, bytes.NewReader(body))


if err != nil {
return nil, err
}


for key, value := range headers {
req.Header.Add(key, value)
}


res, err := client.Do(req)
defer res.Body.Close()


if err != nil {
return nil, err
}


var bodyBytes []byte


if res.StatusCode == 200 {
bodyBytes, err = ioutil.ReadAll(res.Body)
} else if err != nil {
return nil, err
} else {
return nil, fmt.Errorf("The remote end did not return a HTTP 200 (OK) response.")
}


return bodyBytes, nil


}


func getImages(authToken string) ([]string, error) {


type GlanceDetailResponse struct {
Images []struct {
Name   string `json:"name"`
Status string `json:"status"`
ID     string `json:"id"`
}
}


method := "GET"
url := "http://192.168.1.2:9292/v1.1/images/detail"
headers := map[string]string{"X-Auth-Token": authToken}


bodyBytes, err := getBody(method, url, headers, nil)


if err != nil {
return nil, fmt.Errorf("unable to retrieve the response body from the Glance API server: %v", err)
}


var glance GlanceDetailResponse
err = json.Unmarshal(bodyBytes, &glance)


if err != nil {
return nil, fmt.Errorf("unable to parse the JSON response:", err)
}


imageList := make([]string, 10)


for _, image := range glance.Images {
if image.Status == "active" {
imageList = append(imageList, image.ID)
}
}


return imageList, nil


}


func getToken() (string, error) {


type TokenResponse struct {
Auth []struct {
Token struct {
Expires string `json:"expires"`
ID      string `json:"id"`
}
}
}


method := "POST"
url := "http://192.168.1.2:5000/v2.0/tokens"
headers := map[string]string{"Content-type": "application/json"}
creds := []byte(`{"auth":{"passwordCredentials":{"username": "glance", "password":"<password>"}, "tenantId":"<tenantkeygoeshere>"}}`)


bodyBytes, err := getBody(method, url, headers, creds)


if err != nil {
return "", err
}


var keystone TokenResponse
err = json.Unmarshal(bodyBytes, &keystone)


if err != nil {
return "", err
}


authToken := string((keystone.Auth[0].Token.ID))


return authToken, nil
}


func main() {


/*
slog, err := syslog.New(syslog.LOG_ERR, "[fido]")


if err != nil {
log.Fatalf("unable to connect to syslog: %v", err)
os.Exit(1)
} else {
defer slog.Close()
}
*/


hostname, err := os.Hostname()


if err != nil {
// slog.Err("Hostname not captured")
os.Exit(1)
}


authToken, err := getToken()


if err != nil {
// slog.Err("The authentication token from the Glance API server was not retrieved")
os.Exit(1)
}


imageList, err := getImages(authToken)


err = queueImages(hostname, imageList)


if err != nil {
// slog.Err("Could not queue the images for pre-fetching")
os.Exit(1)
}


err = prefetchImages()


if err != nil {
// slog.Err("Could not queue the images for pre-fetching")
os.Exit(1)
}


return
}
369471 次浏览

根据 func (*Client) Do的文件:

”如果由客户端策略(例如 CheckRedirect)引起,或者如果存在 HTTP 协议错误,则返回错误。非2xx 响应不会导致错误。

当 err 为 nil 时,rep 总是包含非 nil rep. Body

然后看这段代码:

res, err := client.Do(req)
defer res.Body.Close()


if err != nil {
return nil, err
}

我猜想 err不是 nil。在检查 err之前,您正在访问 res.Body上的 .Close()方法。

defer只是延迟了函数调用。字段和方法被立即访问。


因此,请立即尝试检查错误。

res, err := client.Do(req)


if err != nil {
return nil, err
}
defer res.Body.Close()

Nil 指针解引用位于第65行,这是

res, err := client.Do(req)
defer res.Body.Close()


if err != nil {
return nil, err
}

如果 err! = nil 那么 res = = nil 和 res。身体恐慌。 在延迟 res.Body 之前处理错误。 Close ()。

自从我来到这里与我的问题,我将添加这个答案,虽然它不完全相关的原始问题。在实现接口时,请确保不要忘记在成员函数声明上添加类型指针。例如:

type AnimalSounder interface {
MakeNoise()
}


type Dog struct {
Name string
mean bool
BarkStrength int
}
    

func (dog *Dog) MakeNoise() {
//implementation
}

我忘记了 (狗 * 狗)的部分,我不推荐它。然后,在类型为 DogAnimalSounder接口变量上调用 MakeNoise时,您就会遇到麻烦。

确保通过发送返回值来处理所有错误。

`if err!=nil{
return nil, err
}`

我知道这可能是一个编码问题,但是对于其他正在寻找另一个答案的人来说,问题在于我让这个程序运行在 powershell 中,并且关闭了 powershell 而没有关闭这个进程。进程使用了相同的端口,因此出现了同样的错误。我必须手动终止这个过程,然后才能正常工作。

对于遇到这个问题的任何人,我有一个类似的问题,我忘记处理一个函数的错误。