我想在一些Go代码中初始化一个包范围的变量来连接到数据库,但是我一直得到一个nil指针异常,所以很明显分配没有正确发生。这会引发错误:
package main
import (
"fmt"
"database/sql"
_ "github.com/lib/pq"
)
var connection *sql.DB
func init() {
connectionString := "host=172.17.0.3 dbname=postgres user=postgres password=postgres port=5432 sslmode=disable"
connection, err := sql.Open(
"postgres",
connectionString,
)
check(err)
err = connection.Ping()
check(err)
}
func main() {
TestConnect()
}
func TestConnect() {
var pid int
err := connection.QueryRow("SELECT pg_backend_pid()").Scan(&pid)
check(err)
fmt.Printf("pid: %v", pid)
}
func check(err error) {
if err != nil {
panic(err)
}
}
这是错误:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4c1a1a]
goroutine 1 [running]:
database/sql.(*DB).conn(0x0, 0x70b7c0, 0xc4200102b8, 0x1, 0xc420055e08, 0x4c28df, 0xc4200b0000)
/usr/local/go/src/database/sql/sql.go:896 +0x3a
database/sql.(*DB).query(0x0, 0x70b7c0, 0xc4200102b8, 0x630335, 0x17, 0x0, 0x0, 0x0, 0x101, 0x741c80, ...)
/usr/local/go/src/database/sql/sql.go:1245 +0x5b
database/sql.(*DB).QueryContext(0x0, 0x70b7c0, 0xc4200102b8, 0x630335, 0x17, 0x0, 0x0, 0x0, 0x0, 0x8, ...)
/usr/local/go/src/database/sql/sql.go:1227 +0xb8
database/sql.(*DB).QueryRowContext(0x0, 0x70b7c0, 0xc4200102b8, 0x630335, 0x17, 0x0, 0x0, 0x0, 0xc420010cb0)
/usr/local/go/src/database/sql/sql.go:1317 +0x90
database/sql.(*DB).QueryRow(0x0, 0x630335, 0x17, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:1325 +0x7c
main.TestConnect()
/home/tom/go/src/go-rest/ignore/connect.go:32 +0x82
main.main()
/home/tom/go/src/go-rest/ignore/connect.go:26 +0x20
exit status 2
但是,如果我将其切换为可以使用=
上的connection
运算符代替:=
...
package main
import (
"fmt"
"database/sql"
_ "github.com/lib/pq"
)
var connection *sql.DB
func init() {
connectionString, err := GetConnectionString()
connection, err = sql.Open(
"postgres",
connectionString,
)
check(err)
err = connection.Ping()
check(err)
}
func main() {
TestConnect()
}
func TestConnect() {
var pid int
err := connection.QueryRow("SELECT pg_backend_pid()").Scan(&pid)
check(err)
fmt.Printf("pid: %v", pid)
}
func GetConnectionString() (string, error) {
return "host=172.17.0.3 dbname=postgres user=postgres password=postgres port=5432 sslmode=disable", nil
}
func check(err error) {
if err != nil {
panic(err)
}
}
然后一切都按预期工作,并正确分配变量。因为先前未定义err
变量,所以我必须使用:=
进行赋值,但这似乎假设我正在初始化函数范围的connection
变量,而不是尝试赋值到包范围的connection
变量。有没有办法在Go中强制执行此任务?就目前而言,我需要编写无用的样板代码以使其以正确的方式工作,并且似乎应该有更好的方法。
当然,这种可能性也表明我正在尝试做一些我不应该做的事情。根据我的研究,this guide似乎建议使用包范围的数据库连接比根据需要创建/关闭连接更好。
答案 0 :(得分:3)
我应该从哪里开始?让我们从您的第一个代码段开始,让它正常工作。
func init() {
connectionString := "host=172.17.0.3 dbname=postgres user=postgres password=postgres port=5432 sslmode=disable"
var err error
connection, err = sql.Open(
"postgres",
connectionString,
)
check(err)
err = connection.Ping()
check(err)
}
在上面的代码段中,err
是局部变量,connection
是包变量。
在您的第二个代码段中,err
被定义为部分connectionString, err := ...
,并且您定义了connection
个包变量。所以它有效。
使用短声明运算符:=
定义本地范围的变量。如:
func
内定义,那么它就是功能范围。if
中定义,那么它是if else
范围。我希望它有所帮助。