doumo2501 2016-04-20 20:34
浏览 158
已采纳

在Golang中将全局变量与Http处理程序配合使用

I know there are some questions and posts/articles regarding this question, but from my newbie view, not exactly. The thing is, I've got a main program listening to a port and redirecting the calls to a specific handler. The typical structure:

func main() {
    http.HandleFunc("/something", specificHandler)
    http.ListenAndServe(":8080", nil)
}

With the handler being something like:

func specificHandler(w http.ResponseWriter, r *http.Request) {
    somepackage.foo()
}

Then somepackage, which contains the function foo, has some global variables, basically because they're needed for functions to share (e.g., when using a priority queue implemented with a container/heap, which will get the priorities in the Swap function from a global matrix of distances which is of course changable). And many other examples. In summary, global variables...

The problem is, as you might see, that those variables are shared among all the calls to the handler. And that's bad.

How can I actually solve this? There must be an easy to way to do it that I haven't got to yet, because it looks like something so usual...

Thanks in advance.


EDIT

To make it clearer. For example, in my A* package, I've got the following global variables:

var openVerticesAS PriorityQueueAStar

// which vertices are closed
var closedVertices map[int]bool

// which vertices are currently open
var openVertices map[int]bool

// cost from start to node
var gScore map[int]float64

// cost from start to end, passing by node i (g+h)
var fScore map[int]float64

Then, PriorityQueueAStar is implemented as follows:

type PriorityQueueAStar []int // rel id

func (pq PriorityQueueAStar) Len() int { return len(pq) }

func (pq PriorityQueueAStar) Empty() bool { return len(pq) == 0 }

func (pq PriorityQueueAStar) Less(i, j int) bool {
    return fScore[pq[i]] < fScore[pq[j]]
}

func (pq PriorityQueueAStar) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueueAStar) Push(x interface{}) {
    *pq = append(*pq, x.(int))
}

func (pq *PriorityQueueAStar) Pop() interface{} {
    old := *pq
    n := len(old)
    rel := old[n-1]
    *pq = old[0 : n-1]
    return rel
}

func (pq PriorityQueueAStar) Top() interface{} {
    return pq[0]
}

The question then, is, how do I keep doing this without having all those maps as global variables? If they are part of the struct, how do I access the struct from the priority queue functions?

  • 写回答

1条回答 默认 最新

  • dongtu0088 2016-04-20 21:27
    关注

    When your handler needs a variable, usually that means you should implement the Handler interface instead of providing a HandlerFunc function.

    Here is a BAD example (using global variables):

    var globalThing string
    
    func specificHandler(w http.ResponseWriter, r *http.Request) {
        w.Write(globalConfigThing)
    }
    
    func main() {
        globalThing = "Hello world!"
        http.HandleFunc("/something", specificHandler)
        http.ListenAndServe(":8080", nil)
    }
    

    Here is a BETTER example (not using global variables):

    type specificHandler struct {
        Thing string
    }
    
    func (h *specificHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        w.Write(h.Thing)
    }
    
    func main() {
        http.Handle("/something", &specificHandler{Thing: "Hello world!"})
        http.ListenAndServe(":8080", nil)
    }
    

    As you can see, a Handler can encapsulate variables.


    For completeness, the other approach is to use a function closure. This works well for once-off handlers but is not re-usable and is harder to write unit tests for.

    func main() {
        scopedThing := "Hello world!"
        http.HandleFunc("/something", func (w http.ResponseWriter, r *http.Request) {
            w.Write(scopedThing)
        })
        http.ListenAndServe(":8080", nil)
    }
    

    Done correctly, you can now avoid global variables in your package somepackage by passing them as arguments, etc.

    EDIT: For example, you can define your handler struct with several PriorityQueueAStar fields from the somepackage package:

    type specificHandler struct {
        QueueA somepackage.PriorityQueueAStar
        QueueB somepackage.PriorityQueueAStar
        QueueC somepackage.PriorityQueueAStar
    }
    
    func (h *specificHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        h.QueueA.Push(h.QueueB.Pop)
        h.QueueB.Push(h.QueueC.Pop)
        w.Write([]byte("Queues pushed and popped"))
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 AT89C51控制8位八段数码管显示时钟。
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 下图接收小电路,谁知道原理
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口