我有这样的代码:
package main import ( "database/sql" "flag" "fmt" "log" "net/http" "os" _ "github.com/go-sql-driver/mysql" ) // Default constant for configuration const DefaultHTTPAddr = ":8080" const DefaultDSN = "root:root@tcp(127.0.0.1:3306)/librarian" // Parameters var ( httpAddr string dsn string db *sql.DB ) // init initializes this package. func init() { flag.StringVar(&httpAddr, "addr", DefaultHTTPAddr, "Set the HTTP bind address") flag.StringVar(&dsn, "dsn", DefaultDSN, "Set the Data Source Name") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [options]\n", os.Args[0]) flag.PrintDefaults() } } type Book struct { id int title string author string } func main() { flag.Parse() var err error db, err := sql.Open("mysql", DefaultDSN) if err != nil { log.Fatal(err) } if err = db.Ping(); err != nil { log.Fatal(err) } // handler http.HandleFunc("/", homepage) http.HandleFunc("/books", booksIndex) log.Println("httpd started successfully") http.ListenAndServe(httpAddr, nil) } func booksIndex(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, http.StatusText(405), 405) return } rows, err := db.Query("SELECT * FROM books") if err != nil { log.Fatal(err) } defer rows.Close() books := make([]*Book, 0) for rows.Next() { bk := new(Book) err = rows.Scan(&bk.id, &bk.title, &bk.author) if err != nil { log.Fatal(err) } books = append(books, bk) } if err = rows.Err(); err != nil { log.Fatal(err) } for _, bk := range books { fmt.Fprintf(w, "%v, %v, %v\n", bk.id, bk.title, bk.author) } } func homepage(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome!") }
每次尝试访问/books它时,总会出现恐慌。
/books
$ curl localhost:8080/books curl: (52) Empty reply from server
像这个:
2016/05/31 11:56:38 http: panic serving 127.0.0.1:51711: runtime error: invalid memory address or nil pointer dereference goroutine 6 [running]: net/http.(*conn).serve.func1(0xc820074100) /usr/local/opt/go/libexec/src/net/http/server.go:1389 +0xc1 panic(0x357b40, 0xc82000a150) /usr/local/opt/go/libexec/src/runtime/panic.go:443 +0x4e9 database/sql.(*DB).conn(0x0, 0xc820010b01, 0xc8200de000, 0x0, 0x0) /usr/local/opt/go/libexec/src/database/sql/sql.go:778 +0xac9 database/sql.(*DB).query(0x0, 0x4022c0, 0x13, 0x0, 0x0, 0x0, 0x3c4601, 0x6, 0x0, 0x0) /usr/local/opt/go/libexec/src/database/sql/sql.go:1073 +0x46 database/sql.(*DB).Query(0x0, 0x4022c0, 0x13, 0x0, 0x0, 0x0, 0xc820016280, 0x0, 0x0) /usr/local/opt/go/libexec/src/database/sql/sql.go:1061 +0xa3 main.booksIndex(0x6979c0, 0xc82006da00, 0xc8200e2000) /Users/rahmatawaludin/gocode/src/github.com/rahmatawaludin/librarian/main.go:68 +0xd9 net/http.HandlerFunc.ServeHTTP(0x4666f8, 0x6979c0, 0xc82006da00, 0xc8200e2000) /usr/local/opt/go/libexec/src/net/http/server.go:1618 +0x3a net/http.(*ServeMux).ServeHTTP(0xc820010ba0, 0x6979c0, 0xc82006da00, 0xc8200e2000) /usr/local/opt/go/libexec/src/net/http/server.go:1910 +0x17d net/http.serverHandler.ServeHTTP(0xc820074080, 0x6979c0, 0xc82006da00, 0xc8200e2000) /usr/local/opt/go/libexec/src/net/http/server.go:2081 +0x19e net/http.(*conn).serve(0xc820074100) /usr/local/opt/go/libexec/src/net/http/server.go:1472 +0xf2e created by net/http.(*Server).Serve /usr/local/opt/go/libexec/src/net/http/server.go:2137 +0x44e
我以为我可以访问db从booksIndex我设置为全局变量。当我将数据库初始化移动到booksIndex错误不会出现。
db
booksIndex
我的代码中哪些部分是错误的?
另外,我是Golang的新手。如果您对如何组织我的代码有任何建议,请告诉我。谢谢.. :)
您的函数中的db变量正在遮盖全局变量。执行此操作时:
db,err:=
它将其分配给新的局部变量db。这是因为它不是来自同一块。根据标准:
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初是在相同类型的同一个块中(如果该块是函数体的话,则在参数列表中)被声明为更早,且类型相同,并且至少有一个非空变量是新的。因此,重新声明只能出现在多变量简短声明中。重新声明不会引入新的变量;它只是为原始值分配一个新值。
因此全局变量仍然是nil指针。当它被访问时,您将获得nil指针取消引用
将其更改为d,然后稍后将其分配给db。还是更正确的(如rahmat的评论所述):=
d , err =
我建议您为处理程序,模型等使用单独的文件。并查看https://github.com/mattermost/platform以了解如何组织代码。