duanhan3067 2019-02-26 10:44
浏览 58
已采纳

运行时错误:无效的内存地址或nil指针取消引用(2)[重复]

This question already has an answer here:

I am new in Go and need help!

In PostgreSQL database I have table called factors. This table has 2 column (factor_id and factor_name). Right now I am successfully connected to PostgreSQL database from Go application.

When I am tring to make query based GET request in console I see error.

http://localhost:8000/api/factors/?limit=5&offset=1

Where I make mistake? Please help me to fix the problem.

controllers/factors.go:

package controllers

import (
    "encoding/json"
    "fmt"
    "net/http"
    "restify/models"
    "restify/utils"
)

var GetFactors = func(res http.ResponseWriter, req *http.Request) {
    data := models.Factors{}

    err := models.GetFactors(&data, req.URL.Query().Get("limit"), req.URL.Query().Get("offset"))
    if err != nil {
        fmt.Println(err.Error())
        http.Error(res, err.Error(), 500)
        return
    }

    out, err := json.Marshal(data)
    if err != nil {
        fmt.Println(err.Error())
        http.Error(res, err.Error(), 501)
        return
    }

    resp := make(map[string]interface{})

    resp["Dictionaries"] = string(out)

    utils.Respond(res, resp)

}

models/factors.go:

package models

import (
    "fmt"
    "restify/database"
)

type Factor struct {
    FactorID int `json:"factor_id"`
    FactorName string `json:"factor_name"`
}

type Factors struct {
    Array[]Factor
}

func GetFactors(data *Factors, limit string, offset string) error {
    rows, err := database.DB.Query(`SELECT * FROM factors ORDER BY factor_id LIMIT ` + limit + ` OFFSET ` + offset + `;`)
    if err != nil {
        fmt.Println(err)
        return err
    }
    defer rows.Close()
    for rows.Next() {
        var id int
        var name string
        model := Factor{}
        err = rows.Scan(&id, &name)
        if err != nil {
            fmt.Println(err)
            return err
        }
        model.FactorID = id
        model.FactorName = name
        data.Array = append(data.Array, model)
    }
    err = rows.Err()
    if err != nil {
        return err
    }
    return nil
}

ERROR:

2019/02/26 16:25:55 http: panic serving [::1]:20932: runtime error: invalid memory address or nil pointer dereference
goroutine 11 [running]:
net/http.(*conn).serve.func1(0xc0002badc0)
    C:/Go/src/net/http/server.go:1746 +0xd7
panic(0x6dad20, 0x970890)
    C:/Go/src/runtime/panic.go:513 +0x1c7
database/sql.(*DB).conn(0x0, 0x78a500, 0xc0000100a8, 0x10000c000339801, 0x0, 0xc000339898, 0xc000339830)
    C:/Go/src/database/sql/sql.go:1081 +0x41
database/sql.(*DB).query(0x0, 0x78a500, 0xc0000100a8, 0xc000356040, 0x3a, 0x0, 0x0, 0x0, 0xc000356001, 0x3a, ...)
    C:/Go/src/database/sql/sql.go:1514 +0x6d
database/sql.(*DB).QueryContext(0x0, 0x78a500, 0xc0000100a8, 0xc000356040, 0x3a, 0x0, 0x0, 0x0, 0x5, 0xc000356040, ...)
    C:/Go/src/database/sql/sql.go:1496 +0xda
database/sql.(*DB).Query(0x0, 0xc000356040, 0x3a, 0x0, 0x0, 0x0, 0x8, 0xc00034e016, 0x1)
    C:/Go/src/database/sql/sql.go:1510 +0x89
restify/models.GetFactors(0xc000339b28, 0xc00034e016, 0x1, 0xc00034e01e, 0x1, 0x0, 0x0)
    C:/Users/NNogerbek/go/src/restify/models/factors.go:18 +0xf6
restify/controllers.glob..func1(0x78a2c0, 0xc00035a000, 0xc000332200)
    C:/Users/NNogerbek/go/src/restify/controllers/factors.go:14 +0xd3
net/http.HandlerFunc.ServeHTTP(0x74da58, 0x78a2c0, 0xc00035a000, 0xc000332200)
    C:/Go/src/net/http/server.go:1964 +0x4b
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0002fc180, 0x78a2c0, 0xc00035a000, 0xc000310300)
    C:/Users/NNogerbek/go/src/github.com/gorilla/mux/mux.go:212 +0xd7
github.com/gorilla/handlers.(*cors).ServeHTTP(0xc0001f2120, 0x78a2c0, 0xc00035a000, 0xc000310300)
    C:/Users/NNogerbek/go/src/github.com/gorilla/handlers/cors.go:54 +0xa95
net/http.serverHandler.ServeHTTP(0xc000056b60, 0x78a2c0, 0xc00035a000, 0xc000310300)
    C:/Go/src/net/http/server.go:2741 +0xb2
net/http.(*conn).serve(0xc0002badc0, 0x78a4c0, 0xc000340040)
    C:/Go/src/net/http/server.go:1847 +0x64d
created by net/http.(*Server).Serve
    C:/Go/src/net/http/server.go:2851 +0x2fc

database/database.go:

package database

import (
    "database/sql"
    "fmt"
    "github.com/joho/godotenv"
    _ "github.com/lib/pq"
    "log"
    "restify/utils"
)

var DB *sql.DB

/*
Function: "Connect".

Description:
The main task of the function is to initialize database connection.
*/
func Open() () {
    // Load environment variables from ".env" file.
    err := godotenv.Load(".env")
    if err != nil {
        panic(err)
    }

    // Initialize database related variables.
    dbUser := utils.CheckEnvironmentVariable("PostgreSQL_USER")
    dbPassword := utils.CheckEnvironmentVariable("PostgreSQL_PASSWORD")
    dbHost := utils.CheckEnvironmentVariable("PostgreSQL_HOST")
    dbName := utils.CheckEnvironmentVariable("PostgreSQL_DATABASE_NAME")

    // Defining connection string for PostgreSQL database.
    dbURL := fmt.Sprintf("user=%s password=%s host=%s dbname=%s sslmode=disable", dbUser, dbPassword, dbHost, dbName)

    // Create PostgreSQL database connection pool.
    DB, err := sql.Open("postgres", dbURL)
    if err != nil {
        panic(err)
    }

    // Ping PostgreSQL database to make sure it's alive.
    err = DB.Ping()
    if err != nil {
        panic(err)
    }

    log.Println("REST API web service successfully connected to remote PostgreSQL database.")
}

/*
Function: "Disconnect"

Description:
The main task of the function is to disconnect database connection.
*/
func Close() error {
    return DB.Close()
}
</div>
  • 写回答

1条回答 默认 最新

  • du8794 2019-02-26 11:11
    关注

    It seems the problem is when DB is assigned here:

    DB, err := sql.Open("postgres", dbURL) 
    

    The DB gets defined in a new scope and hence this creates a local variable rather than setting the pkg level variable. Hence the code Open() establishes a connection to DB.

    Try with this:

    var err error
    DB, err = sql.Open("postgres", dbURL) 
    

    Here is the official quote:

    Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.

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

报告相同问题?