Почему http.HandlerFun c всегда возвращает одно и то же случайное число - PullRequest
1 голос
/ 07 мая 2020

Приветствие от newb ie gopher!

У меня следующая настройка мультиплексора:

s.router.HandleFunc("/test", s.TestHandler())

s.TestHandler:

func (s *server) TestHandler() http.HandlerFunc {
    rnd := rand.Intn(100)
    response := struct {
        RND int `json:"rnd"`
    }{
        rnd,
    }
    return func(w http.ResponseWriter, r *http.Request) {
        s.respond(w, r, 200, response)
        return
    }
}

Вспомогательный метод s.respond:

func (s *server) respond(w http.ResponseWriter, r *http.Request, code int, data interface{}) {
    w.WriteHeader(code)
    if data != nil {
        json.NewEncoder(w).Encode(data)
    }
}

Проблема в том, что когда я запускаю GET / test, я вижу тот же номер, если приложение не перезапускается.

Я уверен Я делаю что-то не так, был бы признателен, если бы кто-нибудь указал на мою ошибку.

1 Ответ

5 голосов
/ 07 мая 2020

Функциональные литералы

Функциональные литералы - это замыкания : они могут ссылаться на переменные, определенные в окружающей функции. Затем эти переменные распределяются между окружающей функцией и функциональным литералом, и они сохраняются, пока доступны.


TestHandler() генерирует одиночное случайное значение а затем возвращает функциональный литерал , т.е. замыкание, которое использует это уже сгенерированное значение для отправки ответа всякий раз, когда оно выполняется маршрутизатором.

Но , окружающая функция замыкания не будет и не имеет причин для выполнения вместе с замыканием всякий раз, когда вызывается замыкание. Окружающая функция выполняется только тогда, когда она вызывается сама, например, когда вы регистрируете обработчик в s.router.HandleFunc("/test", s.TestHandler()), например.

Итак, в предоставленном коде функция rand.Intn в вашем TestHandler вызывается ровно один раз, он не вызывается, как вы, кажется, полагаете, каждый раз, когда вы обращаетесь к серверу с запросом.

Чтобы исправить это, просто переместите код генерации случайных значений на уровень ниже:

func (s *server) TestHandler() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        rnd := rand.Intn(100)
        response := struct {
            RND int `json:"rnd"`
        }{
            rnd,
        }

        s.respond(w, r, 200, response)
    }
}
...