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 鼠标右键,撤销删除 复制 移动,要怎样删除
  • ¥15 使用MATLAB进行余弦相似度计算加速
  • ¥15 服务器安装php5.6版本
  • ¥15 我想用51单片机和数码管做一个从0开始的计数表 我写了一串代码 但是放到单片机里面数码管只闪烁一下然后熄灭
  • ¥20 系统工程中,状态空间模型中状态方程的应用。请猛男来完整讲一下下面所有问题
  • ¥15 我想在WPF的Model Code中获取ViewModel Code中的一个参数
  • ¥15 arcgis处理土地利用道路 建筑 林地分类
  • ¥20 使用visual studio 工具用C++语音,调用openslsx库读取excel文件的sheet问题
  • ¥100 寻会做云闪付tn转h5支付链接的技术
  • ¥15 DockerSwarm跨节点无法访问问题