【问题标题】:How to use global var across files in a package?如何跨包中的文件使用全局变量?
【发布时间】:2016-03-15 16:52:24
【问题描述】:

我的文件结构如下:

models/db.go

type DB struct {
    *sql.DB
}

var db *DB

func init() {
    dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
        DB_USER, DB_PASSWORD, DB_NAME)

    db, err := NewDB(dbinfo)
    checkErr(err)

    rows, err := db.Query("SELECT * FROM profile")
    checkErr(err)

    fmt.Println(rows)
}

func NewDB(dataSourceName string) (*DB, error) {
    db, err := sql.Open("postgres", dataSourceName)
    if err != nil {
        return nil, err
    }
    if err = db.Ping(); err != nil {
        return nil, err
    }
    return &DB{db}, nil
}

models/db_util.go

func (p *Profile) InsertProfile() {
    if db != nil {
        _, err := db.Exec(...)
        checkErr(err)
    } else {
        fmt.Println("DB object is NULL")
    }
}

当我尝试在InsertProfile 函数中访问db 时,它显示NULL ptr exception。如何访问db_utils.go 中的db

我不想将db 大写(因为它会提供对所有包的访问权限)。

我得到了从db 中的init() 正确返回的QUERY。

【问题讨论】:

    标签: pointers go database-connection nullreferenceexception


    【解决方案1】:

    编辑:问题是您使用了Short variable declaration :=,而您只是将创建的*DB 值存储在局部变量中,而不是全局变量中。

    这一行:

    db, err := NewDB(dbinfo)
    

    创建2个局部变量:dberr,而这个局部的db与你的全局db变量无关。您的全局变量将保持为nil。您必须将创建的*DB 分配给全局变量。不要使用简短的变量声明而是简单的assignment,例如:

    var err error
    db, err = NewDB(dbinfo)
    if err != nil {
        log.Fatal(err)
    }
    

    原始答案如下。


    它是一个指针类型,你必须在使用它之前对其进行初始化。指针类型的零值是nil

    您不必导出它(以大写字母开头就是这样做的)。请注意,您拥有多个文件并不重要,只要它们是同一个包的一部分,它们就可以访问彼此定义的标识符。

    一个好的解决方案是在自动调用的包init()函数中进行。

    请注意,sql.Open() 可能只是验证其参数而不创建与数据库的连接。要验证数据源名称是否有效,请调用DB.Ping()

    例如:

    var db *sql.DB
    
    func init() {
        var err error
        db, err = sql.Open("yourdrivername", "somesource")
        if err != nil {
            log.Fatal(err)
        }
        if err = db.Ping(); err != nil {
            log.Fatal(err)
        }
    }
    

    【讨论】:

    • 没错!这就是我正在做的事情。
    • 但在另一个文件中它是 nil。
    • @lionelmessi 我的猜测是您使用了短变量声明:=,并且您只是将创建的*DB 值存储在局部变量中而不是全局变量中。没有看到你的来源就不可能说出来,所以请善待并发布。
    【解决方案2】:

    icza 已经正确回答了您的具体问题,但值得添加一些关于您做错了什么的额外说明,以便您了解如何在未来不犯错误。在 Go 中,用于赋值的语法 := 创建名称在 := 左侧的新变量,可能是影子包,甚至是父范围函数/方法变量。举个例子:

    package main
    
    import "fmt"
    
    var foo string = "global"
    
    func main() {
        fmt.Println(foo) // prints "global"
    
        // using := creates a new function scope variable 
        // named foo that shadows the package scope foo
        foo := "function scope" 
        fmt.Println(foo) // prints "function scope"
        printGlobalFoo() // prints "global"
    
        if true {
            foo := "nested scope"
            fmt.Println(foo) // prints "nested scope"
            printGlobalFoo() // prints "global" 
        } 
        // the foo created inside the if goes out of scope when 
        // the code block is exited
    
        fmt.Println(foo) // prints "function scope"
        printGlobalFoo() // prints "global"
    
        if true {
            foo = "nested scope" // note just = not :=
        }
    
        fmt.Println(foo) // prints "nested scope"
        printGlobalFoo() // prints "global"
    
        setGlobalFoo()
        printGlobalFoo() // prints "new value"
    }
    
    func printGlobalFoo() {
        fmt.Println(foo)
    }
    
    func setGlobalFoo() {
        foo = "new value" // note just = not :=
    }
    

    注意 Go 无法删除或取消设置变量,因此一旦你隐藏了更高范围的变量(例如通过创建与包范围变量同名的函数范围变量),就无法访​​问该代码块中较高范围的变量。

    还要注意:=var foo = 的简写。两者的行为方式完全相同,但是 := 仅在函数或方法中是有效的语法,而 var 语法在任何地方都有效。

    【讨论】:

      【解决方案3】:

      对于谁来这里并想要一个快速的答案。

      db.go 文件中:

      package db
      
      var db *DB
      
      type DB struct {
          *gorm.DB // or what database you want like *mongo.Client
      }
      
      func GetDB() *DB {
          if db == nil{
              db = ConnectToYourDbFunc("connection_string")
          }
          return db
      }
      

      然后在您的其他软件包中,您可以通过以下方式获得它:

      db := db.GetDB()
      

      仅此而已。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-09-27
        • 1970-01-01
        • 1970-01-01
        • 2011-02-25
        • 2013-04-11
        相关资源
        最近更新 更多