pointers - كيفية استخدام فار العالمية عبر الملفات في حزمة؟




go database-connection (2)

لدي بنية الملف التالية:

نماذج / 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

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

عندما أحاول الوصول إلى db في وظيفة InsertProfile ، يقول NULL ptr exception . كيف يمكنني الوصول إلى db في db_utils.go ؟

لا أرغب في استخدام الأحرف الاستهلالية db (لأنها ستتيح الوصول إلى جميع الحزم).

أتلقى QUERY تم إرجاعها من db في init() بشكل صحيح.


أجاب icza بالفعل بشكل صحيح عن مشكلتك المحددة ، لكن الأمر يستحق إضافة بعض التوضيحات الإضافية حول ما تفعله بشكل خاطئ حتى تفهم كيفية عدم ارتكاب الخطأ في المستقبل. في Go ، يقوم بناء الجملة := for الواجب بإنشاء متغيرات جديدة بأسماء على يسار := ، ربما حزمة تظليل ، أو حتى متغيرات دالة / أسلوب نطاق الأصل. كمثال:

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 صالحًا في كل مكان.


تحرير: المشكلة هي أنك استخدمت تعريف متغير قصير := وقمت فقط بتخزين قيمة *DB تم إنشاؤها في متغير محلي وليس في متغير عمومي.

هذا الخط:

db, err := NewDB(dbinfo)

ينشئ متغيرين محليين: db و err ، وهذا 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)
    }
}






nullreferenceexception