我无法弄清楚我是否做了一些愚蠢的事情,或者是否发现了gorm中的错误。尽管我很清楚“无效的内存地址或nil指针取消引用”的含义,但是我完全不知道为什么它出现在这里。
简而言之,我打电话给db.First()我,没有明显原因,我感到恐慌。
db.First()
我的代码的相关位:
package main import ( "fmt" "github.com/gorilla/mux" "github.com/jinzhu/gorm" "net/http" "os" ) type message struct { gorm.Model Title string Body string `sql:"size:0"` // blob } var db = gorm.DB{} // garbage func messageHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) m := message{} query := db.First(&m, vars["id"]) if query.Error != nil { if query.Error == gorm.RecordNotFound { notFoundHandler(w, r) return } else { fmt.Fprintf(os.Stderr, "database query failed: %v", query.Error) internalServerErrorHandler(w, r) return } } // actually do something useful } func main() { db, err := gorm.Open("sqlite3", "/tmp/gorm.db") // ... }
db``main()在包中打开,并存储为包变量。这似乎不太干净,但似乎可以正常工作…
db``main()
恐慌:
2015/07/16 20:56:12 http: panic serving [::1]:37326: runtime error: invalid memory address or nil pointer dereference goroutine 26 [running]: net/http.func·011() /usr/lib/golang/src/net/http/server.go:1130 +0xbb github.com/jinzhu/gorm.(*DB).First(0xd28720, 0x79f220, 0xc2080b2600, 0xc2080ef220, 0x1, 0x1, 0xd) /home/error/go/src/github.com/jinzhu/gorm/main.go:200 +0x154 main.messageHandler(0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /home/error/go/src/myproject/messages.go:28 +0x2c1 net/http.HandlerFunc.ServeHTTP(0x9c3948, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /usr/lib/golang/src/net/http/server.go:1265 +0x41 github.com/gorilla/mux.(*Router).ServeHTTP(0xc2080d9630, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /home/error/go/src/github.com/gorilla/mux/mux.go:98 +0x297 net/http.serverHandler.ServeHTTP(0xc2080890e0, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790) /usr/lib/golang/src/net/http/server.go:1703 +0x19a net/http.(*conn).serve(0xc208051b80) /usr/lib/golang/src/net/http/server.go:1204 +0xb57 created by net/http.(*Server).Serve /usr/lib/golang/src/net/http/server.go:1751 +0x35e
…我的代码的第28行在哪里 query := db.First(&m, vars["id"])
query := db.First(&m, vars["id"])
我检查了gorm和First()函数中的注释行,但这并不是很明显。
First()
return newScope.Set("gorm:order_by_primary_key", "ASC"). inlineCondition(where...).callCallbacks(s.parent.callback.queries).db
为了弄清楚到底发生了什么,我对代码进行了以下更改:
第一次尝试:是否抱怨传递字符串?让我们给它一个整数。毕竟,该示例使用整数。
id, _ := strconv.Atoi(vars["id"]) query := db.First(&m, id)
在完全相同的地方再次出现恐慌。
第二次尝试:我是否m以错误的方式创建了变量?也许确实需要首先分配它new。
m
new
m := new(message) query := db.First(m, vars["id"])
第三次尝试:我只是将要查找的ID硬编码,以防万一大猩猩/多路复用器行为异常。
m := message{} query := db.First(&m, 3)
最后,我用一个空的数据库表进行了测试,其中一个填充的表要求一个存在的ID,而一个填充的表要求一个不存在的ID。在这三种情况下,我都会感到同样的恐慌。
最有趣的部分是,显然net / http正在恢复恐慌,然后notFoundHandler()运行并在浏览器中看到其模板输出。
notFoundHandler()
我目前正在使用mattn / go-sqlite3驱动程序。
我的环境是Fedora RPM软件包中提供的带有cgo 1.4.2的Fedora 22 x86_64。
$ go version go version go1.4.2 linux/amd64 $ go env GOARCH="amd64" GOBIN="" GOCHAR="6" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/error/go" GORACE="" GOROOT="/usr/lib/golang" GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64" CC="gcc" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0" CXX="g++" CGO_ENABLED="1"
这是怎么回事?恐慌是从哪里来的?我如何解决它?
您正在隐藏全局db变量:
db
var db = gorm.DB{} // garbage
您的初始化main()应更改为:
main()
var err error // Note the assignment and not initialise + assign operator db, err = gorm.Open("sqlite3", "/tmp/gorm.db")
否则,db将nil导致恐慌。
nil