I have the following file structure:
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") } }
When I try to access db
in InsertProfile
function, it says NULL ptr exception
. How do I access the db
in db_utils.go
?
I would not like to capitalize db
(as it would give access to all the packages).
I am getting the QUERY returned from the db
in init()
correctly.
A global variable is accessible to all functions in every source file where it is declared. To avoid problems: Initialization — if a global variable is declared in more than one source file in a library, it should be initialized in only one place or you will get a compiler error.
To share global variables across modules within a single program, create a special module. Import the config module in all modules of your application. The module will be available as a global variable across modules.
Edit: The problem is that you used Short variable declaration :=
and you just stored the created *DB
value in a local variable and not in the global one.
This line:
db, err := NewDB(dbinfo)
Creates 2 local variables: db
and err
, and this local db
has nothing to do with your global db
variable. Your global variable will remain nil
. You have to assign the created *DB
to the global variable. Do not use short variable declaration but simple assignment, e.g:
var err error db, err = NewDB(dbinfo) if err != nil { log.Fatal(err) }
Original answer follows.
It's a pointer type, you have to initialize it before you use it. The zero value for pointer types is nil
.
You don't have to export it (that's what starting it with a capital letter does). Note that it doesn't matter that you have multiple files as long as they are part of the same package, they can access identifiers defined in one another.
A good solution would be to do it in the package init()
function which is called automatically.
Note that sql.Open()
may just validate its arguments without creating a connection to the database. To verify that the data source name is valid, call DB.Ping()
.
For example:
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) } }
icza has already correctly answered your specific problem but it's worth adding some additional explanation on what you're doing wrong so you understand how not to make the mistake in the future. In Go, the syntax :=
for assignment creates new variables with the names to the left of the :=
, possibly shadowing package, or even parent scope function/method variables. As an example:
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 := }
Note Go has no way to delete or unset a variable, so once you have shadowed a higher scope variables (such as by creating a function scope variable of the same name as a package scope variable), there is no way to access the higher scope variable within that code block.
Also be aware that :=
is a shorthand for var foo =
. Both act in exactly the same way, however :=
is only valid syntax within a function or method, while the var
syntax is valid everywhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With