2015-12-10 54 views
21

Ho la seguente struttura di file:Come usare var globale su file in un pacchetto?

modelli

/db.go modelli

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 
} 

/db_util.go

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

Quando provo ad accedere db in funzione InsertProfile , dice NULL ptr exception. Come accedere allo db in db_utils.go?

Non vorrei inserire in maiuscolo db (in quanto consentirebbe l'accesso a tutti i pacchetti).

Sto ottenendo correttamente il QUERY restituito da db in init().

risposta

26

Edit: Il problema è che si è utilizzato Short variable declaration:= e basta memorizzato il creato *DB valore in una variabile locale e non in quello globale.

Questa linea:

db, err := NewDB(dbinfo) 

Crea 2 variabili locali: db e err, e questo locale db non ha nulla a che fare con la variabile globale db. La variabile globale rimarrà nil. Devi assegnare lo *DB creato alla variabile globale. Non utilizzare breve dichiarazione della variabile, ma semplice assignment, per esempio:

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

risposta originale segue.


E 'un tipo di puntatore, è necessario inizializzarlo prima di utilizzarlo. Il valore zero per i tipi di puntatore è nil.

Non è necessario esportarlo (è ciò che lo fa inizializzarlo con una lettera maiuscola). Si noti che non importa se si hanno più file fintanto che fanno parte dello stesso pacchetto, possono accedere agli identificatori definiti l'uno nell'altro.

Una buona soluzione sarebbe quella di farlo nella funzione pacchetto init() che viene chiamata automaticamente.

Si noti che sql.Open() può solo convalidare i suoi argomenti senza creare una connessione al database. Per verificare che il nome dell'origine dati sia valido, chiamare DB.Ping().

Ad esempio:

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

esattamente! Questo è quello che sto facendo. – lionelmessi

+0

eppure è nullo nell'altro file. – lionelmessi

+1

@lionelmessi La mia ipotesi sarebbe che tu abbia usato una breve dichiarazione di variabili ': =' e hai appena memorizzato il valore di '* DB' creato in una variabile locale e non in quella globale. Impossibile dirlo senza vedere la tua fonte, quindi per favore sii gentile e pubblicalo. – icza

10

icza ha già risposto correttamente il tuo problema specifico, ma ne vale la pena di aggiungere qualche spiegazione aggiuntiva su quello che stai facendo male in modo da capire come non fare l'errore in futuro.In Go, la sintassi := per l'assegnazione crea nuove variabili con i nomi a sinistra del pacchetto , eventualmente ombreggiato o anche variabili funzione/metodo dell'ambito genitore. Per fare un esempio:

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 non ha alcun modo di eliminare o disinserire una variabile, quindi una volta che avete in ombra un più alto variabili portata (come ad esempio con la creazione di una variabile funzione di campo di applicazione lo stesso nome di una variabile ambito pacchetto), non è possibile accedere alla variabile di ambito superiore all'interno di tale blocco di codice.

Si noti inoltre che := è una stenografia per var foo =. Entrambi agiscono esattamente allo stesso modo, tuttavia := è solo sintassi valida all'interno di una funzione o metodo, mentre la sintassi var è valida ovunque.

Problemi correlati