web-dev-qa-db-fra.com

Comment utiliser la var globale entre les fichiers d'un paquet?

J'ai la structure de fichier suivante:

modèles/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")
    }
}

Lorsque j'essaie d'accéder à la fonction db dans la fonction InsertProfile, elle indique NULL ptr exception. Comment accéder à db dans db_utils.go?

Je ne voudrais pas capitaliser db (car cela donnerait accès à tous les paquets).

Je reçois correctement la requête QUERY renvoyée par db dans init().

29
lionelmessi

Edit: Le problème est que vous avez utilisé Déclaration de variable courte:= Et que vous venez de stocker le *DB Valeur dans une variable locale et non dans la variable globale.

Cette ligne:

db, err := NewDB(dbinfo)

Crée 2 variables locales: db et err, et cette locale db n'a rien à voir avec votre variable globale db. Votre variable globale restera nil. Vous devez affecter le *DB Créé à la variable globale. N'utilisez pas de déclaration de variable courte mais simple affectation , par exemple:

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

La réponse originale suit.


C'est un type de pointeur, vous devez l'initialiser avant de l'utiliser. La valeur zéro pour les types de pointeur est nil.

Vous n’avez pas à l’exporter (c’est ce qui commence par une majuscule). Notez que vous avez plusieurs fichiers dans la mesure où ils font partie du même package, ils peuvent accéder aux identifiants définis les uns dans les autres.

Une bonne solution serait de le faire dans le package init(), qui est appelée automatiquement.

Notez que sql.Open() peut simplement valider ses arguments sans créer de connexion à la base de données. Pour vérifier que le nom de la source de données est valide, appelez DB.Ping() .

Par exemple:

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

icza a déjà répondu correctement à votre problème spécifique, mais il est utile d’ajouter quelques explications sur ce que vous faites de travers pour que vous compreniez bien comment ne pas commettre l’erreur à l’avenir. Dans Go, la syntaxe := for assign crée de nouvelles variables avec les noms situés à gauche du :=, éventuellement un package d'observation, ou même des variables fonction/méthode de la portée parente. Par exemple:

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 :=
}

Remarque Go n'a aucun moyen de supprimer ou de supprimer une variable. Par conséquent, une fois que vous avez observé une variable de portée supérieure (par exemple, en créant une variable de portée de fonction du même nom qu'une variable de portée de package), vous ne pouvez plus accéder à la portée supérieure. variable dans ce bloc de code.

Sachez également que := est un raccourci pour var foo =. Les deux agissent exactement de la même manière, cependant := n'est qu'une syntaxe valide dans une fonction ou une méthode, alors que la syntaxe var est valide partout.

12
Endophage