2016-04-20 25 views
3

Ich weiß, es gibt einige Fragen und Beiträge/Artikel zu dieser Frage, aber aus meiner Newbie-Ansicht, nicht genau. Die Sache ist, ich habe ein Hauptprogramm, das auf einen Port hört und die Anrufe an einen bestimmten Handler umleitet. Die typische Struktur:Verwendung von globalen Variablen mit Http Handler in Golang

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

Mit dem Handler ist so etwas wie:

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

Dann somepackage, die die Funktion foo enthält, hat einige globale Variablen, im Grunde, weil sie gebraucht werden Funktionen, die geteilt werden sollen (zB wenn eine mit einem Container/Heap implementierte Prioritätswarteschlange verwendet wird, die die Prioritäten in der Swap-Funktion aus einer globalen Matrix von Entfernungen erhält, die natürlich änderbar ist). Und viele andere Beispiele. Zusammengefasst, globale Variablen ...

Das Problem ist, wie Sie vielleicht sehen, dass diese Variablen unter allen Aufrufen an den Handler gemeinsam sind. Und das ist schlecht.

Wie kann ich das tatsächlich lösen? Es muss ein einfacher Weg sein, es zu tun, den ich noch nicht habe, weil es so etwas wie gewöhnlich aussieht ...

Vielen Dank im Voraus.


EDIT

es deutlicher zu machen. Zum Beispiel in meinem A * Paket habe ich die folgenden globalen Variablen bekam:

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 

Dann PriorityQueueAStar wird wie folgt implementiert:

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] 
} 

Die Frage ist dann, wird, wie zu tun Ich mache das weiter, ohne all diese Karten als globale Variablen zu haben? Wenn ich Teil der Struktur bin, wie greife ich aus den Funktionen der Prioritätswarteschlange auf die Struktur zu?

+0

die Tatsache, dass Sie erkennen, Sie haben Variablen mod sein Wenn zwischen verschiedenen Anrufen unterschieden wird, zeigt dies an, dass es sich um das Design handelt. Klingt so, als ob du irgendeine Art von Container willst. Sie sollten eine Struktur entwerfen, die Ihren Anforderungen entspricht, und diese Struktur an Aufrufe Ihrer Funktionen in einem Paket übergeben. –

+0

Ja, das klingt gut, oder erstellen Sie eine Struktur für das gesamte Paket und lassen Sie es die Variablen enthalten. Aber was ist mit Funktionen wie Less (i, j int) von der Heap-Schnittstelle? Diese müssen auf die Struktur zugreifen und ich sehe keine Möglichkeit, sie an sie weiterzugeben ... – jcasado94

+0

Schauen Sie in die Kanäle [chan] (https://golang.org/ref/spec#Channel_types), die lösen eine Menge * von Problemen im Zusammenhang mit der gemeinsamen Nutzung von Speicher. – miltonb

Antwort

4

Wenn Ihr Handler eine Variable benötigt, bedeutet das normalerweise, dass Sie die Schnittstelle Handler implementieren sollten, anstatt eine HandlerFunc-Funktion bereitzustellen.

Hier ist ein schlechtes Beispiel (globale Variablen):

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) 
} 

Hier ist ein besseres Beispiel (nicht globale Variablen):

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) 
} 

Wie Sie sehen können, kann ein Handler kapseln Variablen.


Der Vollständigkeit halber ist der andere Ansatz, einen Funktionsabschluss zu verwenden. Dies funktioniert gut für einmalige Handler, ist aber nicht wiederverwendbar und es ist schwieriger Komponententests zu erstellen.

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

richtig gemacht, Sie jetzt globale Variablen in Ihrem Paket somepackage, indem sie als Argumente vermeiden usw.

EDIT: Zum Beispiel können Sie Ihre Handler-Struktur mit mehreren definieren PriorityQueueAStar Felder aus der somepackage Paket:

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

Genau das habe ich vermisst. Handler als Strukturen, die Variablen kapseln. Danke, ich muss jetzt daran arbeiten! ;) – jcasado94

+0

Sorry, schnelle Frage. Ich habe es geschafft, der Struktur alle Funktionen hinzuzufügen, um eine Container/Heap-Prioritätswarteschlange darin zu implementieren (Len, Push, Pop, ...), und es funktioniert gut für einen. Was aber, wenn ich zwei oder mehr Container/Heap-Objekte in derselben Struktur implementieren muss? Wie kann ich diese Funktionen für alle definieren? Vielen Dank. – jcasado94

+0

Betten Sie eine Struktur in eine andere Struktur ein. – elithrar