2016-04-20 54 views
3

我知道有關於這個問題的一些問題和文章/文章,但是從我的新手視圖來看,並不完全。 事情是,我有一個主程序監聽一個端口並將調用重定向到一個特定的處理程序。典型結構:在Golang中使用Http處理程序的全局變量

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

隨着處理程序是這樣的:

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

然後somepackage,其中包含的功能,有一些全局變量,主要是因爲他們需要函數共享(例如,當使用用容器/堆實現的優先級隊列時,該優先級隊列將從距離的全局矩陣中獲得交換函數中的優先級,當然這是可改變的)。還有很多其他的例子。總之,全局變量...

問題是,如你所見,這些變量是在處理程序的所有調用中共享的。這很糟糕。

我該如何解決這個問題?必須有一個簡單的方法來做到這一點,我還沒有到,因爲它看起來像平常一樣......

在此先感謝。


編輯

使其更清晰。舉例來說,在我的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

事實上,你認識到你的變量是mod在不同的通話之間進行通話表明這是設計。聽起來像你想要某種容器。你會想要設計一個結構來適應你的需求,並將這個結構傳遞給某些包中的函數調用。 –

+0

是的,這聽起來不錯,或者爲整個包創建一個結構並讓它包含變量。但是堆函數中的Less(i,j int)函數呢?那些將需要訪問該結構,我不認爲有辦法將它傳遞給他們... – jcasado94

+0

調查頻道[chan](https://golang.org/ref/spec#Channel_types)他們解決了很多*與共享內存相關的問題。 – miltonb

回答

4

當您的處理程序需要一個變量時,通常意味着您應該實現Handler接口,而不是提供HandlerFunc函數。

這裏是(使用全局變量)一個壞榜樣:

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")) 
} 
+0

這正是我錯過的東西。處理程序作爲封裝變量的結構體。謝謝,現在就開始工作吧! ;) – jcasado94

+0

對不起,快速提問。我已經成功地將所有函數添加到結構中,以在其中實現容器/堆優先級隊列(Len,Push,Pop,...),並且它適用於其中一個。但是如果我需要在同一個結構中實現兩個或多個容器/堆對象呢?我如何爲所有這些函數定義這些函數?謝謝。 – jcasado94

+0

將結構嵌入另一個結構中。 – elithrar

相關問題