GAE Go, init () - вызывать его несколько раз? - PullRequest
4 голосов
/ 30 января 2012

Я пишу приложение Google App Engine Go. В нем я хочу обрабатывать некоторые вызовы отдельно в разных файлах .go. Должен ли я вызывать функцию init () отдельно в каждом из этих файлов или просто объявить ее в одном файле и вызывать некоторые другие функции для инициализации каждого файла .go?

Например, если бы у меня было два файла, user.go:

package User

import(
    "http"
    "fmt"
)

func init() {
    http.HandleFunc("/", hello)
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, user!")
}

И admin.go:

package Admin

import(
    "http"
    "fmt"
)

func init() {
    http.HandleFunc("/admin/", hello)
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, admin!")
}

Является ли такая инициализация правильной, или она рекомендована против чего-то подобного?

Ответы [ 2 ]

10 голосов
/ 30 января 2012

В соответствии со спецификацией языка Go:

  • весь код инициализации выполняется в одной процедуре, а функции

  • init () внутри один пакет выполняется в неуказанном порядке

В вашем случае пакеты Пользователь и Администратор независимы (Пользователь не импортирует Администратора, а Администратор не импортирует Пользователя).Это означает, что:

  • две функции init () в User и Admin выполняются в неопределенном порядке

Соединение тел двух функций init () водна функция init () будет выглядеть следующим образом:

func init() {
    http.HandleFunc("/", User.Hello)
    http.HandleFunc("/admin/", Admin.Hello)
}

Обратите внимание, что не имеет значения, регистрирует ли программа сначала "/" или "/admin/".Таким образом, следующий код также действителен:

func init() {
    http.HandleFunc("/admin/", Admin.Hello)
    http.HandleFunc("/", User.Hello)
}

Из приведенных выше двух фрагментов кода видно, что нормально вызывать http.HandleFunc("/", ...) и http.HandleFunc("/admin/", ...) в неопределенном порядке.


Поскольку "/" и "/admin/" могут быть зарегистрированы в любом порядке, и все функции init () выполняются в одной процедуре, ответ на ваш вопрос: Да, такая инициализация правильная.

1 голос
/ 01 февраля 2012

Я думаю, что ваш вопрос действительно касается дизайна упаковки.Я не могу точно сказать по вашему вопросу, но вы также можете путать пакеты и исходные файлы.Чтобы уточнить: пакет состоит из одного или нескольких исходных файлов в одном каталоге, определяет логическую единицу функциональности, включая общедоступные API и частные внутренние представления данных.

Если вас интересует специфика init (), вот соответствующие части спецификации

Пакет без импорта инициализируется путем присвоения начальных значений всем его переменным уровня пакета и последующего вызова любой функции уровня пакета с именем и подписьюиз

func init ()

определено в его источнике.

У вас есть два пакета, определенных в вашем коде выше, поэтому также применимо следующее:

Если пакет имеет импорт, импортированные пакеты инициализируются перед инициализацией самого пакета.

Что говорит о том, существует ли зависимость администратора от пользователя (или наоборот), которая будетопределить порядок, в котором выполняются два вызова init ().Никакая такая зависимость не приведет к выполнению вызовов init () в неуказанном порядке.

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

Некоторые вопросы, которые вы могли бы задать себе:

  • Существуют ли две отдельные (бизнес) функции, которые должны быть представлены?
  • Нужно ли предоставлять отдельные публичные API?
  • Какие-либо организационные причины для разделения разных пакетов (разных кодеров)?
  • Планируете ли вы повторно использовать код в одном или нескольких пакетах независимо от другого?
...