0

我正在尝试使用以下代码来理解 golang 中的变量范围。在此示例中,在 http 中调用页面将回显 uri 查询以及 Boltdb 中存储的值。

问题是数据库驱动程序似乎没有在 http 处理程序上下文中正确运行:它不会将任何内容打印到 stdout 或 http 请求。

我期待它打印:

他喜欢 <'uri query content'> 但更喜欢披萨(来自 bolt.db 驱动程序的数据)

如何修复此代码?包主

import (
    "fmt"
    "net/http"
    "log"
    "github.com/boltdb/bolt"
)

var db bolt.DB

func handler(w http.ResponseWriter, r *http.Request) {
    dberr := db.Update(func(tx *bolt.Tx) error {
    log.Println("here")
        b := tx.Bucket([]byte("MyBucket"))
            loving := b.Get([]byte("loving"))
        log.Printf("He's loving %s but prefers %s",r.URL.Path[1:], string(loving))
            fmt.Fprintf(w,"He's loving %s but prefers %s",r.URL.Path[1:], string(loving) )
        return nil
    })
    if dberr != nil {
        fmt.Errorf("db update: %s", dberr)
    }
    log.Printf("Finished handling")
}

func main() {

    db, err := bolt.Open("my.db", 0600, nil)
    if err != nil {
        log.Fatal(err)
    }else{
        log.Println("database opened")
    }
    dberr := db.Update(func(tx *bolt.Tx) error {
        b, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
        if err != nil {
        return fmt.Errorf("create bucket: %s", err)
        }
        err2 := b.Put([]byte("loving"), []byte("pizza"))
        if err2 != nil {
        return fmt.Errorf("put loving: %s", err2)
        }
        loving := b.Get([]byte("loving"))
        log.Printf("He's loving %s", string(loving))
        return nil
    })

        if dberr != nil {
        fmt.Errorf("db update: %s", err)
        }
    defer db.Close()

    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)

   }
4

1 回答 1

2

我想我看到了你的错误。这通常有点难以跟踪,因为它只是:在 equals 的前面。这基本上是一个范围问题,因为您声明db为全局变量,同时创建了一个db范围为您的主函数的变量。

您曾经db, err := ...分配值而不是仅分配=. :=将声明和推断类型。由于它也在进行声明,因此db您在main函数中使用的不是db您在全局范围内声明的。同时,处理程序仍在尝试使用db在全局范围内声明的 。下面的代码与您最初的代码相同,在代码中添加了一些注释来概述工作更改是什么。希望这可以帮助!

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/boltdb/bolt"
)

var db *bolt.DB // this is going to be a pointer and is going to be nil until its set by the main function

func handler(w http.ResponseWriter, r *http.Request) {
    dberr := db.Update(func(tx *bolt.Tx) error {
        log.Println("here")
        b := tx.Bucket([]byte("MyBucket"))
        loving := b.Get([]byte("loving"))
        log.Printf("He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
        fmt.Fprintf(w, "He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
        return nil
    })
    if dberr != nil {
        fmt.Errorf("db update: %s", dberr)
    }
    log.Printf("Finished handling")
}

func main() {
    var err error                           // this will have to be declared because of the next line to assign db the first value returned from `bolt.Open`
    db, err = bolt.Open("my.db", 0600, nil) // notice that this has changed and is no longer `db, err := ...` rather its `db, err = ...`
    if err != nil {
        log.Fatal(err)
    } else {
        log.Println("database opened")
    }
    dberr := db.Update(func(tx *bolt.Tx) error {
        b, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
        if err != nil {
            return fmt.Errorf("create bucket: %s", err)
        }
        err2 := b.Put([]byte("loving"), []byte("pizza"))
        if err2 != nil {
            return fmt.Errorf("put loving: %s", err2)
        }
        loving := b.Get([]byte("loving"))
        log.Printf("He's loving %s", string(loving))
        return nil
    })

    if dberr != nil {
        fmt.Errorf("db update: %s", err)
    }
    defer db.Close()

    http.HandleFunc("/", handler)
    http.ListenAndServe(":3000", nil)
}
于 2015-10-18T15:37:54.283 回答