pointers - guia - qgis español
¿Cómo usar var global entre archivos en un paquete? (2)
icza ya ha respondido correctamente su problema específico, pero vale la pena agregar alguna explicación adicional sobre lo que está haciendo mal para que entienda cómo no cometer el error en el futuro.
En Go, la sintaxis
:=
para la asignación crea nuevas variables con los nombres a la izquierda del
:=
, posiblemente sombreando el paquete, o incluso variables de función / método de alcance padre.
Como ejemplo:
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 :=
}
Nota Go no tiene forma de eliminar o desarmar una variable, por lo que una vez que haya sombreado las variables de un alcance más alto (como al crear una variable de alcance de función con el mismo nombre que una variable de alcance de paquete), no hay forma de acceder al alcance más alto variable dentro de ese bloque de código.
También tenga en cuenta que
:=
es una abreviatura de
var foo =
.
Sin embargo, ambos actúan exactamente de la misma manera
:=
solo es una sintaxis válida dentro de una función o método, mientras que la sintaxis
var
es válida en todas partes.
Tengo la siguiente estructura de archivos:
modelos / 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
}
modelos / db_util.go
func (p *Profile) InsertProfile() {
if db != nil {
_, err := db.Exec(...)
checkErr(err)
} else {
fmt.Println("DB object is NULL")
}
}
Cuando intento acceder a
db
en la función
InsertProfile
, dice
NULL ptr exception
.
¿Cómo
db_utils.go
a la base de
db_utils.go
en
db_utils.go
?
No me gustaría capitalizar
db
(ya que daría acceso a todos los paquetes).
Recibo la CONSULTA devuelta de la base de datos en
init()
correctamente.
Editar:
El problema es que usó la
declaración de variable corta
:=
y simplemente almacenó el valor
*DB
creado en una variable local y no en la global.
Esta línea:
db, err := NewDB(dbinfo)
Crea 2 variables locales:
db
y
err
, y este
db
local no tiene nada que ver con su variable global
db
.
Su variable global seguirá siendo
nil
.
Debe asignar el
*DB
creado a la variable global.
No use una declaración de variable corta sino una
assignment
simple, por ejemplo:
var err error
db, err = NewDB(dbinfo)
if err != nil {
log.Fatal(err)
}
La respuesta original sigue.
Es un tipo de puntero, debe inicializarlo antes de usarlo.
El valor cero para los tipos de puntero es
nil
.
No tiene que exportarlo (eso es lo que comienza con una letra mayúscula). Tenga en cuenta que no importa que tenga varios archivos siempre que formen parte del mismo paquete, pueden acceder a los identificadores definidos entre sí.
Una buena solución sería hacerlo en la función de paquete
init()
que se llama automáticamente.
Tenga en cuenta que
sql.Open()
puede simplemente validar sus argumentos sin crear una conexión a la base de datos.
Para verificar que el nombre de la fuente de datos es válido, llame a
DB.Ping()
.
Por ejemplo:
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)
}
}