2016-04-20 4 views
3

Я знаю, что есть некоторые вопросы и сообщения/статьи по этому вопросу, но из моего новичка, а не точно. Дело в том, что у меня есть основная программа, слушая порт и перенаправляя вызовы к определенному обработчику. Типичная структура:Использование глобальных переменных с обработчиками Http в Golang

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

С обработчика нечто вроде:

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

Тогда somepackage, который содержит функцию Foo, имеет некоторые глобальные переменные, в основном потому, что они необходимы для функции для совместного использования (например, при использовании очереди приоритетов, реализованной с контейнером/кучей, которая получит приоритеты в функции Swap из глобальной матрицы расстояний, которая, конечно, может меняться). И многие другие примеры. Итак, глобальные переменные ...

Проблема заключается в том, что эти переменные разделяются между всеми вызовами обработчика. И это плохо.

Как я могу это решить? Должен быть простой способ сделать это, что я еще не получил, потому что он выглядит как-то так привычно ...

Заранее спасибо.


EDIT

Чтобы сделать его более четким. Например, в моем 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

Тот факт, что вы признаете, у вас есть переменные быть мод ified между разными вызовами указывает, что это дизайн. Похоже, вы хотите какой-то контейнер. Вы захотите создать структуру, соответствующую вашим потребностям, и передать эту структуру в вызовы ваших функций в somepackage. –

+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, передавая их в качестве аргументов и т.д.

EDIT: Например, вы можете определить обработчик-структуру с несколькими 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