Лучший способ начать работу с Go — сразу приступить к делу. В этой главе я объясню, как подготовить среду разработки Go, а также создать и запустить простое веб-приложение. Цель этой главы — получить представление о том, на что похоже написание на Go, поэтому не беспокойтесь, если вы не понимаете всех используемых функций языка. Все, что вам нужно знать, подробно объясняется в последующих главах.
Настройка сцены
Домашняя страница с информацией о вечеринке
Форма, которую можно использовать для RSVP, которая будет отображать страницу благодарности
Проверка заполнения формы RSVP
Сводная страница, которая показывает, кто придет на вечеринку
В этой главе я создаю проект Go и использую его для создания простого приложения, которое содержит все эти функции.
Вы можете загрузить пример проекта для этой главы — и для всех остальных глав этой книги — с https://github.com/apress/pro-go
. См. Главу 2 о том, как получить помощь, если у вас возникнут проблемы с запуском примеров.
Установка средств разработки
Первым шагом является установка инструментов разработки Go. Перейдите на https://golang.org/dl
и загрузите установочный файл для вашей операционной системы. Установщики доступны для Windows, Linux и macOS. Следуйте инструкциям по установке, которые можно найти по адресу https://golang.org/doc/install
для вашей платформы. Когда вы завершите установку, откройте командную строку и выполните команду, показанную в листинге 1-1, которая подтвердит, что инструменты Go были установлены, распечатав версию пакета.
Go активно разрабатывается, и существует постоянный поток новых выпусков, а это значит, что к тому времени, когда вы будете читать эту книгу, может быть доступна более поздняя версия. Go имеет прекрасную политику поддержки совместимости, поэтому у вас не должно возникнуть проблем с примерами из этой книги, даже в более поздних версиях. Если у вас возникнут проблемы, см. репозиторий этой книги на GitHub, https://github.com/apress/pro-go
, где я буду публиковать бесплатные обновления, устраняющие критические изменения.
Для меня (и для Apress) обновление такого рода является продолжающимся экспериментом, и оно продолжает развиваться — не в последнюю очередь потому, что я не знаю, что будет содержать будущие версии Go. Цель состоит в том, чтобы продлить жизнь этой книги, дополнив содержащиеся в ней примеры.
Проверка установки Go
Неважно, видите ли вы другой номер версии или другую информацию об операционной системе — важно то, что команда go
работает и выдает результат.
Установка Git
Некоторые команды Go полагаются на систему контроля версий Git. Перейдите на https://git-scm.com
и следуйте инструкциям по установке для вашей операционной системы.
Выбор редактора кода
Единственный другой шаг — выбрать редактор кода. Файлы исходного кода Go представляют собой обычный текст, что означает, что вы можете использовать практически любой редактор. Однако некоторые редакторы предоставляют специальную поддержку для Go. Наиболее популярным выбором является Visual Studio Code, который можно использовать бесплатно и который поддерживает новейшие функции языка Go. Visual Studio Code — это редактор, который я рекомендую, если у вас еще нет предпочтений. Visual Studio Code можно загрузить с http://code.visualstudio.com
, и существуют установщики для всех популярных операционных систем. Вам будет предложено установить расширения Visual Studio Code для Go, когда вы начнете работу над проектом в следующем разделе.
Если вам не нравится код Visual Studio, вы можете найти список доступных опций по адресу https://github.com/golang/go/wiki/IDEsAndTextEditorPlugins
. Для выполнения примеров из этой книги не требуется специального редактора кода, и все задачи, необходимые для создания и компиляции проектов, выполняются в командной строке.
Создание проекта
partyinvites
. Перейдите в папку partyinvites
и выполните команду, показанную в листинге 1-2, чтобы запустить новый проект Go.
Запуск проекта Go
Команда go
используется почти для каждой задачи разработки, как я объясню в Главе 3. Эта команда создает файл с именем go.mod
, который используется для отслеживания пакетов, от которых зависит проект, а также может использоваться для публикации проекта, если необходимо.
.go
. Используйте выбранный вами редактор для создания файла с именем main.go
в папке partyinvites
с содержимым, показанным в листинге 1-3. Если вы используете Visual Studio Code и впервые редактируете файл Go, вам будет предложено установить расширения, поддерживающие язык Go.
Содержимое файла main.go в папке partyinvites
Синтаксис Go будет вам знаком, если вы использовали любой C или C-подобный язык, например C# или Java. В этой книге я подробно описываю язык Go, но вы можете многое понять, просто взглянув на ключевые слова и структуру кода в листинге 1-3.
Функции сгруппированы в пакеты (package
), поэтому в листинге 1-3 есть оператор пакета. Зависимости пакетов создаются с помощью оператора импорта, который позволяет получить доступ к функциям, которые они используют, в файле кода. Операторы сгруппированы в функции, которые определяются с помощью ключевого слова func
. В листинге 1-3 есть одна функция, которая называется main
. Это точка входа для приложения, что означает, что это точка, с которой начнется выполнение, когда приложение будет скомпилировано и запущено.
Функция main
содержит один оператор кода, который вызывает функцию с именем Println
, предоставляемую пакетом с именем fmt
. Пакет fmt
является частью обширной стандартной библиотеки Go, описанной во второй части этой книги. Функция Println
выводит строку символов.
partyinvites
, чтобы скомпилировать и выполнить проект. (Обратите внимание, что в этой команде после слова run
стоит точка.)
go run
полезна во время разработки, поскольку выполняет задачи компиляции и выполнения за один шаг. Приложение выдает следующий вывод:
package main import "fmt" func main() { fmt.Println("TODO: add some features") }
Ставим фигурную скобку на новую строку в файле main.go в папке partyinvites
# partyinvites .\main.go:5:6: missing function body .\main.go:6:1: syntax error: unexpected semicolon or newline before {
Go настаивает на определенном стиле кода и необычным образом обрабатывает распространенные элементы кода, такие как точки с запятой. Подробности синтаксиса Go описаны в следующих главах, но сейчас важно точно следовать приведенным примерам, чтобы избежать ошибок.
Определение типа данных и коллекции
package main import "fmt" type Rsvp struct { Name, Email, Phone string WillAttend bool } func main() { fmt.Println("TODO: add some features"); }
Определение типа данных в файле main.go в папке partyinvites
Go позволяет определять пользовательские типы и присваивать им имена с помощью ключевого слова type
. В листинге 1-6 создается тип данных struct
с именем Rsvp
. Структуры позволяют группировать набор связанных значений. Структура Rsvp
определяет четыре поля, каждое из которых имеет имя и тип данных. Типы данных, используемые полями Rsvp
, — string
и bool
, которые являются встроенными типами для представления строки символов и логических значений. (Встроенные типы Go описаны в главе 4.)
Далее мне нужно собрать вместе значения Rsvp
. В последующих главах я объясню, как использовать базу данных в приложении Go, но для этой главы будет достаточно хранить ответы в памяти, что означает, что ответы будут потеряны при остановке приложения.
Определение среза в файле main.go в папке partyinvites
Этот новый оператор основан на нескольких функциях Go, которые проще всего понять, если начать с конца оператора и прорабатывать в обратном направлении.
make
, которая используется в листинге 1-7 для инициализации нового среза. Последние два аргумента функции make
— это начальный размер и начальная емкость.
Я указал ноль для аргумента размера, чтобы создать пустой срез. Размеры срезов изменяются автоматически по мере добавления новых элементов, а начальная емкость определяет, сколько элементов можно добавить, прежде чем размер среза нужно будет изменить. В этом случае к срезу можно добавить десять элементов, прежде чем его размер нужно будет изменить.
make
указывает тип данных, для хранения которого будет использоваться срез:
Квадратные скобки []
обозначают срез. Звездочка *
обозначает указатель. Часть типа Rsvp
обозначает тип структуры, определенный в листинге 1-6. В совокупности []*Rsvp
обозначает срез указателей на экземпляры структуры Rsvp
.
Вы, возможно, вздрогнули от термина указатель, если вы пришли к Go из C# или Java, которые не позволяют использовать указатели напрямую. Но вы можете расслабиться, потому что Go не допускает операций над указателями, которые могут создать проблемы для разработчика. Как я объясню в главе 4, использование указателей в Go определяет только то, копируется ли значение при его использовании. Указав, что мой срез будет содержать указатели, я говорю Go не создавать копии моих значений Rsvp
, когда я добавляю их в срез.
Ключевое слово var
указывает, что я определяю новую переменную, которой присваивается имя responses
. Знак равенства, =
, является оператором присваивания Go и устанавливает значение переменной responses
для вновь созданного среза. Мне не нужно указывать тип переменной responses
, потому что компилятор Go выведет его из присвоенного ей значения.
Создание HTML-шаблонов
layout.html
в папку partyinvites
с содержимым, показанным в листинге 1-8.
Содержимое файла layout.html в папке partyinvites
Этот шаблон будет макетом, содержащим содержимое, общее для всех ответов, которые будет создавать приложение. Он определяет базовый HTML-документ, включая элемент link
(ссылки), указывающий таблицу стилей из CSS-фреймворка Bootstrap, которая будет загружаться из сети распространения контента (CDN). Я продемонстрирую, как обслуживать этот файл из папки в главе 24, но для простоты в этой главе я использовал CDN. Пример приложения по-прежнему будет работать в автономном режиме, но вы увидите элементы HTML без стилей, показанных на рисунках.
Двойные фигурные скобки в листинге 1-8, {{
и }}
, используются для вставки динамического содержимого в выходные данные, созданные шаблоном. Используемое здесь выражение block
(блок) определяет содержимое заполнителя, которое будет заменено другим шаблоном во время выполнения.
welcome.html
в папку partyinvites
с содержимым, показанным в листинге 1-9.
Содержимое файла welcome.html в папке partyinvites
form.html
в папку partyinvites
с содержимым, показанным в листинге 1-10.
Содержимое файла form.html в папке partyinvites
thanks.html
в папку partyinvites
с содержимым, показанным в листинге 1-11.
Содержимое файла thanks.html в папке partyinvites
sorry.html
в папку partyinvites
с содержимым, показанным в листинге 1-12.
Содержимое файла sorry.html в папке partyinvites
list.html
в папку partyinvites
с содержимым, показанным в листинге 1-13.
Содержимое файла list.html в папке partyinvites
Загрузка шаблонов
Загрузка шаблонов из файла main.go в папку partyinvites
Первое изменение относится к оператору импорта import
и объявляет зависимость от функций, предоставляемых пакетом html/template
, который является частью стандартной библиотеки Go. Этот пакет поддерживает загрузку и отображение HTML-шаблонов и подробно описан в главе 23.
templates
. Тип значения, присваиваемого этой переменной, выглядит сложнее, чем есть на самом деле:
Ключевое слово map
обозначает карту, тип ключа которой указывается в квадратных скобках, за которым следует тип значения. Тип ключа для этой карты — string
, а тип значения — *template.Template
, что означает указатель на структуру Template
, определенную в пакете шаблона. Когда вы импортируете пакет, для доступа к его функциям используется последняя часть имени пакета. В этом случае доступ к функциям, предоставляемым пакетом html/template
, осуществляется с помощью шаблона, и одной из этих функций является структура с именем Template
. Звездочка указывает на указатель, что означает, что карта использует string
ключи, используемые для хранения указателей на экземпляры структуры Template
, определенной пакетом html/template
.
Затем я создал новую функцию с именем loadTemplates
, которая пока ничего не делает, но будет отвечать за загрузку файлов HTML, определенных в предыдущих листингах, и их обработку для создания значений *template.Template
, которые будут храниться на карте. Эта функция вызывается внутри функции main
. Вы можете определять и инициализировать переменные непосредственно в файлах кода, но самые полезные функции языка можно реализовать только внутри функций.
loadTemplates
. Каждый шаблон загружается с макетом, как показано в листинге 1-15, что означает, что мне не нужно повторять базовую структуру HTML-документа в каждом файле.
Загрузка шаблонов из файла main.go в папку partyinvites
loadTemplates
определяет переменные, используя краткий синтаксис Go, который можно использовать только внутри функций. Этот синтаксис определяет имя, за которым следует двоеточие (:
), оператор присваивания (=
) и затем значение:
Этот оператор создает переменную с именем templateNames
, и ее значение представляет собой массив из пяти строковых значений, которые выражены с использованием литеральных значений. Эти имена соответствуют именам файлов, определенных ранее. Массивы в Go имеют фиксированную длину, и массив, присвоенный переменной templateNames
, может содержать только пять значений.
for
с использованием ключевого слова range
, например:
range
используется с ключевым словом for
для перечисления массивов, срезов и карт. Операторы внутри цикла for
выполняются один раз для каждого значения в источнике данных, которым в данном случае является массив, и этим операторам присваиваются два значения для работы:
Переменной index
присваивается позиция значения в массиве, который в настоящее время перечисляется. Переменной name
присваивается значение в текущей позиции. Тип первой переменной всегда int
, это встроенный тип данных Go для представления целых чисел. Тип другой переменной соответствует значениям, хранящимся в источнике данных. Перечисляемый в этом цикле массив содержит строковые значения, что означает, что переменной name
будет присвоена строка в позиции в массиве, указанной значением индекса.
for
загружает шаблон:
html/templates
предоставляет функцию ParseFiles
, которая используется для загрузки и обработки HTML-файлов. Одной из самых полезных и необычных возможностей Go является то, что функции могут возвращать несколько результирующих значений. Функция ParseFiles
возвращает два результата: указатель на значение template.Template
и ошибку, которая является встроенным типом данных для представления ошибок в Go. Краткий синтаксис для создания переменных используется для присвоения этих двух результатов переменным, например:
t
, а ошибка присваивается переменной с именем err
. Это распространенный шаблон в Go, и он позволяет мне определить, был ли загружен шаблон, проверив, равно ли значение err
nil
, что является нулевым значением Go:
Если err
равен nil
, я добавляю на карту пару ключ-значение, используя значение name
в качестве ключа и *template.Tempate
, назначенный t
в качестве значения. Go использует стандартную нотацию индекса для присвоения значений массивам, срезам и картам.
Если значение err
не равно nil
, то что-то пошло не так. В Go есть функция panic
, которую можно вызвать при возникновении неисправимой ошибки. Эффект вызова panic
может быть разным, как я объясню в главе 15, но для этого приложения он будет иметь эффект записи трассировки стека и прекращения выполнения.
go run.
; вы увидите следующий вывод по мере загрузки шаблонов:
Создание обработчиков HTTP и сервера
/
, и когда им предоставляется список участников, который будет запрошен с путем URL-адреса /list
, как показано в листинге 1-16.
Определение обработчиков начальных запросов в файле main.go в папке partyinvites
net/http
, который является частью стандартной библиотеки Go. Функции, обрабатывающие запросы, должны иметь определенную комбинацию параметров, например:
Второй аргумент — это указатель на экземпляр структуры Request
, определенной в пакете net/http
, который описывает обрабатываемый запрос. Первый аргумент — это пример интерфейса, поэтому он не определен как указатель. Интерфейсы определяют набор методов, которые может реализовать любой тип структуры, что позволяет писать код для использования любого типа, реализующего эти методы, которые я подробно объясню в главе 11.
Одним из наиболее часто используемых интерфейсов является Writer
, который используется везде, где можно записывать данные, такие как файлы, строки и сетевые подключения. Тип ResponseWriter
добавляет дополнительные функции, относящиеся к работе с ответами HTTP.
ResponseWriter
, полученный функциями, определенными в листинге 1-16, может использоваться любым кодом, который знает, как записывать данные с использованием интерфейса Writer
. Это включает в себя метод Execute
, определенный типом *Template
, который я создал при загрузке шаблонов, что упрощает использование вывода от рендеринга шаблона в ответе HTTP:
Этот оператор считывает *template.Template
из карты, назначенной переменной templates
, и вызывает определенный им метод Execute
. Первый аргумент — это ResponseWriter
, куда будут записываться выходные данные ответа, а второй аргумент — это значение данных, которое можно использовать в выражениях, содержащихся в шаблоне.
net/http
определяет функцию HandleFunc
, которая используется для указания URL-адреса и обработчика, который будет получать соответствующие запросы. Я использовал HandleFunc
для регистрации своих новых функций-обработчиков, чтобы они реагировали на URL-пути /
и /list
:
Создание HTTP-сервера в файле main.go в папке partyinvites
ListenAndServe
. Второй аргумент равен nil
, что говорит серверу, что запросы должны обрабатываться с использованием функций, зарегистрированных с помощью функции HandleFunc
. Запустите команду, показанную в листинге 1-18, в папке partyinvites
, чтобы скомпилировать и выполнить проект.
Компиляция и выполнение проекта
http://localhost:5000
, что даст ответ, показанный на рисунке 1-1. (Если вы используете Windows, вам может быть предложено подтвердить разрешение брандмауэра Windows, прежде чем запросы смогут быть обработаны сервером. Вам нужно будет предоставлять одобрение каждый раз, когда вы используете команду go run .
в этой главе. В последующих главах представлен простой сценарий PowerShell для решения этой проблемы.)

Обработка HTTP-запросов
Нажмите Ctrl+C, чтобы остановить приложение, как только вы подтвердите, что оно может дать ответ.
Написание функции обработки формы
/form
, на который он нацелен, нет обработчика. В листинге 1-19 определяется новая функция-обработчик и начинается реализация функций, необходимых приложению.
Добавление функции обработчика форм в файл main.go в папке partyinvites
form.html
ожидает получить определенную структуру данных значений данных для отображения своего содержимого. Для представления этой структуры я определил новый тип структуры с именем formData
. Структуры Go могут быть больше, чем просто группа полей «имя-значение», и одна из предоставляемых ими функций — поддержка создания новых структур с использованием существующих структур. В этом случае я определил структуру formData
, используя указатель на существующую структуру Rsvp
, например:
В результате структуру formData
можно использовать так, как будто она определяет поля Name
, Email
, Phone
и WillAttend
из структуры Rsvp
, и я могу создать экземпляр структуры formData
, используя существующее значение Rsvp
. Звездочка обозначает указатель, что означает, что я не хочу копировать значение Rsvp
при создании значения formData
.
request.Method
, которое возвращает тип полученного HTTP-запроса. Для GET-запросов выполняется шаблон form
, например:
formData
, используя значения по умолчанию для ее полей:
new
, а значения создаются с помощью фигурных скобок, при этом значения по умолчанию используются для любого поля, для которого значение не указано. Поначалу такой оператор может быть трудно разобрать, но он создает структуру formData
путем создания нового экземпляра структуры Rsvp
и создания среза строк, не содержащего значений. Амперсанд (символ &
) создает указатель на значение:
formData
была определена так, чтобы ожидать указатель на значение Rsvp
, которое мне позволяет создать амперсанд. Запустите команду, показанную в листинге 1-20, в папке partyinvites
, чтобы скомпилировать и выполнить проект.
Компиляция и выполнение проекта
http://localhost:5000
и нажмите кнопку RSVP Now. Новый обработчик получит запрос от браузера и отобразит HTML-форму, показанную на рисунке 1-2.

Отображение HTML-формы
Обработка данных формы
formHandler
; остальная часть файла main.go
остается неизменной.
Обработка данных формы в файле main.go в папке partyinvites
ParseForm
обрабатывает данные формы, содержащиеся в HTTP-запросе, и заполняет карту, доступ к которой можно получить через поле Form
. Затем данные формы используются для создания значения Rsvp
:
Этот оператор демонстрирует, как структура создается со значениями для ее полей, в отличие от значений по умолчанию, которые использовались в листинге 1-19. HTML-формы могут включать несколько значений с одним и тем же именем, поэтому данные формы представлены в виде среза значений. Я знаю, что для каждого имени будет только одно значение, и я обращаюсь к первому значению в срезе, используя стандартную нотацию индекса с отсчетом от нуля, которую используют большинство языков.
Rsvp
, я добавляю его в срез, присвоенный переменной responses
:
Функция append
используется для добавления значения к срезу. Обратите внимание, что я использую амперсанд для создания указателя на созданное значение Rsvp
. Если бы я не использовал указатель, то мое значение Rsvp
дублировалось бы при добавлении в срез.
Остальные операторы используют значение поля WillAttend
для выбора шаблона, который будет представлен пользователю.
partyinvites
, чтобы скомпилировать и выполнить проект.
Компиляция и выполнение проекта
http://localhost:5000
и нажмите кнопку RSVP Now. Заполните форму и нажмите кнопку Submit RSVP; вы получите ответ, выбранный на основе значения, которое вы выбрали с помощью элемента выбора HTML. Щелкните ссылку в ответе, чтобы просмотреть сводку ответов, полученных приложением, как показано на рисунке 1-3.

Обработка данных формы
Добавление проверки данных
formHandler
, а остальная часть файла main.go
осталась неизменной.
Проверка данных формы в файле main.go в папке partyinvites
Приложение получит пустую строку (""
) из запроса, если пользователь не предоставит значение для поля формы. Новые операторы в листинге 1-23 проверяют поля Name
, EMail
и Phone
и добавляют сообщение к срезу строк для каждого поля, не имеющего значения. Я использую встроенную функцию len
, чтобы получить количество значений в срезе ошибок, и если есть ошибки, я снова визуализирую содержимое шаблона form
, включая сообщения об ошибках в данных, которые получает шаблон. Если ошибок нет, то используется шаблон thanks
или sorry
.
partyinvites
, чтобы скомпилировать и выполнить проект.
Компиляция и выполнение проекта
http://localhost:5000
и нажмите кнопку RSVP Now. Нажмите кнопку Submit RSVP, не вводя никаких значений в форму; вы увидите предупреждающие сообщения, как показано на рисунке 1-4. Введите некоторые данные в форму и отправьте ее снова, и вы увидите окончательное сообщение.

Проверка данных
Резюме
В этой главе я установил пакет Go и использовал содержащиеся в нем инструменты для создания простого веб-приложения, используя только один файл кода и несколько основных шаблонов HTML. Теперь, когда вы увидели Go в действии, следующая глава поместит эту книгу в контекст.