我知道有关于这个问题的一些问题和帖子/文章,但从我的新手观点来看,并不完全正确。 问题是,我有一个主程序监听端口并将调用重定向到特定的处理程序。典型的结构:
func main() {
http.HandleFunc("/something", specificHandler)
http.ListenAndServe(":8080", nil)
}
处理程序类似于:
func specificHandler(w http.ResponseWriter, r *http.Request) {
somepackage.foo()
}
然后 somepackage ,其中包含函数 foo ,有一些全局变量,主要是因为它们需要共享函数(例如,当使用优先级时)使用容器/堆实现的队列,它将从全局矩阵矩阵中获取Swap函数中的优先级,这当然是可变的。还有很多其他的例子。总之,全局变量......
问题是,正如您可能看到的那样,这些变量在对处理程序的所有调用之间共享。那太糟糕了。
我怎样才能真正解决这个问题?我必须有一个容易实现的方法,因为它看起来像是平常......
提前致谢。
修改
让它更清晰。例如,在我的A *包中,我有以下全局变量:
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
然后, PriorityQueueAStar 按如下方式实施:
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]
}
接下来的问题是,如何在不将所有这些地图作为全局变量的情况下继续这样做?如果它们是结构的一部分,我如何从优先级队列函数访问结构?
答案 0 :(得分:6)
当您的处理程序需要变量时,通常这意味着您应该实现Handler
接口而不是提供HandlerFunc
函数。
这是一个BAD示例(使用全局变量):
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)
}
这是一个更好的例子(不使用全局变量):
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)
}
如您所见,Handler
可以封装变量。
为了完整性,另一种方法是使用函数闭包。这适用于一次性处理程序,但不能重复使用,并且更难编写单元测试。
func main() {
scopedThing := "Hello world!"
http.HandleFunc("/something", func (w http.ResponseWriter, r *http.Request) {
w.Write(scopedThing)
})
http.ListenAndServe(":8080", nil)
}
正确完成后,您现在可以通过将它们作为参数等传递来避免包somepackage
中的全局变量。
编辑:例如,您可以使用PriorityQueueAStar
包中的多个somepackage
字段定义处理程序结构:
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"))
}
答案 1 :(得分:0)
chowey 提到了闭包方法,但有一个警告,即它不可测试或可重用。如果你有一个返回闭包的函数,它实际上是可测试和可重用的。对于某些类型的数据,这可能会使抽象和实现更加清晰:
func handleThing(thing string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Write(thing)
}
}
func main() {
http.HandleFunc("/something", handleThing("Hello world!"))
http.ListenAndServe(":8080", nil)
}