donglao9606 2017-08-04 03:57
浏览 69
已采纳

Golang init()函数中的程序包范围的变量分配

I want to initialize a package-wide variable in some Go code to connect to a database, but I keep getting a nil pointer exception, so clearly the assignment isn't occurring properly. This throws an error:

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)
    }
}

Here's the error:

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

However, if I switch it up so I can use the = operator on connection instead of :=...

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)
    }
}

Then everything works as expected, and the variable is properly assigned. Because the err variable is previously undefined, I have to use := for assignment, but this seems to assume that I'm initializing a function-scoped connection variable, and not trying to assign to the package-scoped connection variable. Is there a way to force this assignment in Go? As it stands, I need to write useless, boilerplate code to get this to work the right way, and it seems like there should be a better way.

Of course, the possibility also stands that I'm trying to do something that I perhaps shouldn't be. Based on my research though, this guide seems to suggest using a package-wide database connection is better then creating / closing connections as needed.

  • 写回答

1条回答 默认 最新

  • douwen0647 2017-08-04 04:56
    关注

    Where should I start? Let's start with your first code snippet and make it work properly.

    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)
    }
    

    In the above code snippet err is local variable and connection is package variable.


    In your second code snippet err is defined as part connectionString, err := ... and you have connection package variable defined. So it works.


    Using short declaration operator := defines local scoped variable. Such as:

    • If you define within func then it is function scope.
    • If you define in if then it is if else scope.

    I hope it helps.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)