2015-12-10 9 views
21

I次のファイル構造を持っている:パッケージ内のファイル全体でglobal varを使用するにはどうすればよいですか?

モデル/ 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 
} 

モデル/ db_util.go私はInsertProfile機能でdbにアクセスしよう

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

それはNULL ptr exceptionと言います。 db_utils.godbにアクセスするにはどうすればよいですか?

dbを大文字にしたくないです(すべてのパッケージにアクセスできるようになります)。

dbから返されたQUERYが正しくinit()に返されています。

答えて

26

編集:問題はあなたがShort variable declaration:=を使用し、あなただけのローカル変数ではなくグローバルな1で作成し*DB値を格納していることです。

このライン:

db, err := NewDB(dbinfo) 

が2つのローカル変数を作成:dberrを、このローカルdbがあなたのグローバルdb変数とは何の関係もありません。グローバル変数はnilのままです。作成した*DBをグローバル変数に割り当てる必要があります。短い変数宣言を使用せず、単純なassignmentを使用してください。例えば、

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

オリジナルの回答が続きます。


これはポインタ型です。使用する前に初期化する必要があります。ポインタ型のゼロ値はnilです。

エクスポートする必要はありません(大文字で始めるのはこれです)。同じパッケージの一部である限り、複数のファイルを持っていても、互いに定義された識別子にアクセスできます。

自動的に呼び出される機能init()のパッケージで良い解決策があります。

sql.Open()は、データベースへの接続を作成しなくても、引数を検証することができます。データソース名が有効であることを確認するには、DB.Ping()に電話してください。例えば

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

正確に!これは私がやっていることです。 – lionelmessi

+0

まだ他のファイルではnilです。 – lionelmessi

+1

@lionelmessi私は、短い変数宣言 ':='を使用して、作成した '* DB'値をローカル変数に保存しただけで、グローバル変数ではないと思います。あなたのソースを見ずに話すことはできませんので、親切にして投稿してください。 – icza

10

iczaはすでに正しく特定の問題に答えていますが、それはあなたがそうあなたが将来的に間違いをしないようにする方法を理解間違ってやっていることのいくつかの追加の説明を加える価値があります。Goでは、代入の構文:=は、:=の左側にある名前を持つ新しい変数を作成します。場合によってはシャドーパッケージ、または親スコープの関数/メソッド変数も作成されます。例として:

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

(注)このようなパッケージスコープ変数と同じ名前の関数スコープの変数を作成することで、より高いスコープ変数を(影にいるかつてのでGoは、変数を削除したり、設定を解除する方法はありません)、そのコードブロック内の上位スコープ変数にアクセスする方法はありません。

:=は、var foo =の省略形です。両方とも全く同じように動作しますが、:=は関数またはメソッド内でのみ有効な構文ですが、varの構文はどこでも有効です。

関連する問題