从另一个包调用资源时出现运行时恐慌

Runtime panic on calling resource from another package

我正在尝试使用 fiber + zap + pgx 创建一个简单的 API 服务器 我遇到无法解决的错误。

PS C:\Users\risharan\Documents\GitHub\freya> go run .\src\freya.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0xcdca67]

goroutine 1 [running]:
go.uber.org/zap.(*Logger).check(0x0, 0xc000060500, 0xff0b96, 0x15, 0x0)
        C:/Users/risharan/go/pkg/mod/go.uber.org/zap@v1.18.1/logger.go:268 +0x987
go.uber.org/zap.(*Logger).Info(0x0, 0xff0b96, 0x15, 0x0, 0x0, 0x0)
        C:/Users/risharan/go/pkg/mod/go.uber.org/zap@v1.18.1/logger.go:191 +0x4b
freya/src/db.Init()
        C:/Users/risharan/Documents/GitHub/freya/src/db/db.go:19 +0x6db
main.init.0()
        C:/Users/risharan/Documents/GitHub/freya/src/freya.go:15 +0x31
exit status 2

目前的代码是;

// 主程序包

func init() {
    logger.Init()
    env.Init()
    db.Init()
}

func main() {

    app := fiber.New()

    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World!")
    })

    log.Fatal(app.Listen(":3000"))
}

// 包记录器

var Say *zap.Logger

func Init() {
    Say, _ := zap.NewProduction()
    defer Say.Sync()
}

// 包数据库

var Conn *pgxpool.Pool

func Init() {
    c, err := pgxpool.Connect(context.Background(), env.Conf["DATABASE_URL"])
    if err != nil {
        logger.Say.Fatal("Can't connect to DB", zap.String("Details", err.Error()))
    } else {
        logger.Say.Info("Connected to Database")
    }
    Conn = c

    defer Conn.Close()

    var greeting string
    err = Conn.QueryRow(context.Background(), "select 'Hello, this is db!'").Scan(&greeting)
    if err != nil {
        logger.Say.Error("DB Query failed", zap.String("Details", err.Error()))
    }
    logger.Say.Info("Connected to DB. DB says; ", zap.String("Details", greeting))

}

错误信息指示的行

        C:/Users/risharan/Documents/GitHub/freya/src/db/db.go:19 +0x6db
main.init.0()
        C:/Users/risharan/Documents/GitHub/freya/src/freya.go:15 +0x31

是:

func init() {
    logger.Init()
    env.Init()
    db.Init() // this is the line 15 as shown in error message in package main
}

func Init() {
    c, err := pgxpool.Connect(context.Background(), env.Conf["DATABASE_URL"])
    if err != nil {
        logger.Say.Fatal("Can't connect to DB", zap.String("Details", err.Error()))
    } else {
        logger.Say.Info("Connected to Database") // this is the line 19 in the error message in the package db
    }

到目前为止,go 的错误消息很难解码,我不确定我在这里做错了什么,或者我应该如何修复我的代码。

注意:我被告知要进行依赖注入 arch。我个人认为该模式相当复杂,而且由于我仍在学习围棋,所以我宁愿暂时保持它尽可能简单。所以宁愿不要建议我切换模式的答案,除非无法修复当前基于全局变量的模式。

你的各种Init()函数中至少有两个问题。

  1. 您正在使用 :=,它在函数范围内声明了一个 new 变量,并且不会修改您在外部声明的变量范围。

  2. 您在 Init() 中使用 defer,这是在 Init() returns 时执行延迟函数的地方。这基本上意味着您的 Init 创建然后销毁资源,使其对任何后续代码都无用。


如果你想赋值给在外部作用域中声明的变量,请不要使用 :=,而是使用 =。如果您打算在该函数之外使用 conn,请不要在初始化函数内执行 defer conn.Close() 之类的操作。

var Say *zap.Logger

func Init() {
    Say, _ = zap.NewProduction()
}
var Conn *pgxpool.Pool

func Init() {
    c, err := pgxpool.Connect(context.Background(), env.Conf["DATABASE_URL"])
    if err != nil {
        logger.Say.Fatal("Can't connect to DB", zap.String("Details", err.Error()))
    } else {
        logger.Say.Info("Connected to Database")
    }
    Conn = c

    var greeting string
    err = Conn.QueryRow(context.Background(), "select 'Hello, this is db!'").Scan(&greeting)
    if err != nil {
        logger.Say.Error("DB Query failed", zap.String("Details", err.Error()))
    }
    logger.Say.Info("Connected to DB. DB says; ", zap.String("Details", greeting))
}
func init() {
    logger.Init()
    env.Init()
    db.Init()
}

func main() {
    defer func() {
        db.Conn.Close()
        logger.Say.Sync()
    }()

    app := fiber.New()

    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World!")
    })

    log.Fatal(app.Listen(":3000"))
}