versiones guia español actualizar pointers go database-connection nullreferenceexception

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) } }