Как писать код на Go
Введение
Этот документ демонстрирует разработку простого Go пакета внутри модуля и знакомит с инструментом go, стандартным способом получения, сборки и установки Go модулей, пакетов и команд.
Организация кода
Программы на Go организованы в пакеты. Пакет — это коллекция исходных файлов в одном каталоге, которые компилируются вместе. Функции, типы, переменные и константы, определённые в одном исходном файле, видны всем другим исходным файлам внутри того же пакета.
Репозиторий содержит один или несколько модулей. Модуль — это коллекция связанных Go пакетов, которые
выпускаются вместе. Обычно Go репозиторий содержит только один модуль, расположенный в корне репозитория. Файл с
именем go.mod объявляет путь модуля: префикс импортного пути для всех пакетов внутри модуля.
Модуль содержит пакеты в каталоге, содержащем его файл go.mod, а также подкаталоги этого каталога, до
следующего подкаталога, содержащего другой файл go.mod (если такой существует).
Обратите внимание, что вам не нужно публиковать свой код в удалённом репозитории, чтобы его можно было собрать. Модуль может быть определён локально без принадлежности к репозиторию. Однако хорошей практикой является организация кода так, как если бы вы собирались опубликовать его когда-нибудь.
Путь каждого модуля служит не только префиксом импортного пути для его пакетов, но и указывает, где команда
go должна искать его для загрузки. Например, чтобы загрузить модуль golang.org/x/tools,
команда go обратится к репозиторию, указанному по адресу https://golang.org/x/tools
(подробнее здесь).
Импортный путь — это строка, используемая для импорта пакета. Импортный путь пакета — это путь модуля,
объединённый с подкаталогом внутри модуля. Например, модуль github.com/google/go-cmp содержит пакет в
каталоге cmp/. Импортный путь этого пакета — github.com/google/go-cmp/cmp. Пакеты
стандартной библиотеки не имеют префикса пути модуля.
Ваша первая программа
Чтобы скомпилировать и запустить простую программу, сначала выберите путь модуля (мы будем использовать example/user/hello)
и создайте файл go.mod, объявляющий его:
$ mkdir hello # Альтернативно, клонируйте его, если он уже существует в системе контроля версий. $ cd hello $ <b>go mod init example/user/hello</b> go: creating new go.mod: module example/user/hello $ cat go.mod module example/user/hello go 1.16 $
Первая инструкция в исходном файле Go должна быть
package name. Исполняемые команды всегда должны использовать
package main.
Далее создайте файл с именем hello.go внутри этой директории, содержащий
следующий код Go:
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
Теперь вы можете собрать и установить эту программу с помощью инструмента go:
$ <b>go install example/user/hello</b> $
Эта команда собирает команду hello, создавая исполняемый бинарный файл.
Затем она устанавливает этот бинарный файл как $HOME/go/bin/hello (или,
в Windows, %USERPROFILE%\go\bin\hello.exe).
Каталог установки управляется переменными среды
GOPATH и GOBIN среды выполнения.
Если установлена переменная GOBIN, бинарные файлы устанавливаются в этот каталог.
Если установлена переменная GOPATH, бинарные файлы устанавливаются в подкаталог
bin первого каталога в списке GOPATH.
В противном случае, бинарные файлы устанавливаются в подкаталог bin
стандартного GOPATH ($HOME/go или %USERPROFILE%\go).
Вы можете использовать команду go env для переносимой установки значения
переменной среды по умолчанию для будущих команд go:
$ go env -w GOBIN=/somewhere/else/bin $
Чтобы удалить переменную, ранее установленную с помощью go env -w, используйте go env -u:
$ go env -u GOBIN $
Команды, такие как go install, применяются в контексте модуля,
содержащего текущую рабочую директорию. Если рабочая директория не находится внутри
модуля example/user/hello, команда go install может завершиться ошибкой.
Для удобства, команды go принимают пути относительно рабочей директории
и по умолчанию используют пакет в текущей рабочей директории, если другой путь не указан.
Таким образом, в нашей рабочей директории следующие команды эквивалентны:
$ go install example/user/hello
$ go install .
$ go install
Далее, давайте запустим программу, чтобы убедиться, что она работает. Для удобства,
мы добавим каталог установки в переменную PATH, чтобы сделать запуск бинарных файлов простым:
# Пользователям Windows следует обратиться к /wiki/SettingGOPATH
# для установки %PATH%.
$ <b>export PATH=$PATH:$(dirname $(go list -f '{{.Target}}' .))</b>
$ <b>hello</b>
Hello, world.
$
Если вы используете систему контроля версий, теперь будет хорошим временем инициализировать репозиторий, добавить файлы и зафиксировать ваше первое изменение. Опять же, этот шаг является необязательным: использовать систему контроля версий для написания кода на Go не обязательно.
$ <b>git init</b> Initialized empty Git repository in /home/user/hello/.git/ $ <b>git add go.mod hello.go</b> $ <b>git commit -m "initial commit"</b> [master (root-commit) 0b4507d] initial commit 1 file changed, 7 insertion(+) create mode 100644 go.mod hello.go $
go команда находит репозиторий, содержащий указанный путь модуля, запрашивая соответствующий HTTPS URL
и читая метаданные, встроенные в HTML-ответ (см.
go help importpath).
Многие сервисы хостинга уже предоставляют эти метаданные для репозиториев, содержащих код на Go, поэтому самый
простой способ сделать ваш модуль доступным для использования другими — это сделать так, чтобы путь модуля совпадал
с URL репозитория.
Импорт пакетов из вашего модуля
Давайте создадим пакет morestrings и используем его в программе hello.
Сначала создайте директорию для пакета под названием
$HOME/hello/morestrings, а затем файл с именем
reverse.go в этой директории со следующим содержимым:
// Package morestrings implements additional functions to manipulate UTF-8
// encoded strings, beyond what is provided in the standard "strings" package.
package morestrings
// ReverseRunes returns its argument string reversed rune-wise left to right.
func ReverseRunes(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
Поскольку функция ReverseRunes начинается с заглавной буквы, она является
экспортируемой,
и может быть использована в других пакетах, которые импортируют пакет morestrings.
Давайте проверим, что пакет компилируется с помощью go build:
$ cd $HOME/hello/morestrings $ <b>go build</b> $
Эта команда не создаст выходной файл. Вместо этого она сохранит скомпилированный пакет в локальном кэше сборки.
После того как вы убедились, что пакет morestrings успешно собирается, давайте используем его в
программе hello. Для этого измените ваш исходный файл
$HOME/hello/hello.go, чтобы он использовал пакет morestrings:
package main
import (
"fmt"
<b>"example/user/hello/morestrings"</b>
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}
Установите программу hello:
$ <b>go install example/user/hello</b>
Запустив новую версию программы, вы должны увидеть новое, перевёрнутое сообщение:
$ <b>hello</b> Hello, Go!
Импорт пакетов из удалённых модулей
Путь импорта может описывать, как получить исходный код пакета с помощью системы управления версиями, такой как Git
или Mercurial. Инструмент go использует это свойство для автоматического получения пакетов из удалённых
репозиториев.
Например, чтобы использовать github.com/google/go-cmp/cmp в вашей программе:
package main
import (
"fmt"
"example/user/hello/morestrings"
"github.com/google/go-cmp/cmp"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
Теперь, когда у вас появилась зависимость от внешнего модуля, необходимо загрузить этот модуль и записать его версию
в файл go.mod. Команда go mod tidy добавляет недостающие требования к модулям для
импортируемых пакетов и удаляет требования к модулям, которые больше не используются.
$ go mod tidy go: finding module for package github.com/google/go-cmp/cmp go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.5.4 $ go install example/user/hello $ hello Hello, Go! string( - "Hello World", + "Hello Go", ) $ cat go.mod module example/user/hello go 1.16 <b>require github.com/google/go-cmp v0.5.4</b> $
Зависимости модулей автоматически скачиваются в подкаталог pkg/mod каталога, указанного переменной
окружения GOPATH. Содержимое скачанного модуля для заданной версии разделяется между всеми другими
модулями, которые требуют эту версию, поэтому команда go помечает эти файлы и каталоги как доступные
только для чтения. Чтобы удалить все загруженные модули, можно передать флаг -modcache команде go
clean:
$ go clean -modcache $
Тестирование
Go имеет лёгкую систему тестирования, состоящую из команды go test и пакета testing.
Тест пишется путём создания файла с именем, заканчивающимся на _test.go, который содержит функции с
именами TestXXX с сигнатурой func (t *testing.T).
Фреймворк тестирования запускает каждую такую функцию; если функция вызывает функцию, обозначающую сбой, такую как
t.Error или t.Fail, то тест считается не пройденным.
Добавьте тест в пакет morestrings, создав файл
$HOME/hello/morestrings/reverse_test.go, содержащий следующий код на Go.
package morestrings
import "testing"
func TestReverseRunes(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := ReverseRunes(c.in)
if got != c.want {
t.Errorf("ReverseRunes(%q) == %q, want %q", c.in, got, c.want)
}
}
}
Затем запустите тест с помощью команды go test:
$ cd $HOME/hello/morestrings $ <b>go test</b> PASS ok example/user/hello/morestrings 0.165s $
Выполните команду go help test и ознакомьтесь с
документацией пакета testing для получения дополнительной информации.
Дальнейшие шаги
Подпишитесь на рассылку golang-announce, чтобы получать уведомления о выходе новых стабильных версий Go.
См. Effective Go для советов по написанию ясного, идиоматического Go кода.
Пройдите A Tour of Go чтобы изучить язык.
Посетите страницу документации для набора подробных статей о языке Go и его библиотеках и инструментах.
Получение помощи
Для получения помощи в реальном времени, задавайте вопросы полезным gophers в сообществе gophers Slack server (забрать приглашение можно здесь).
Официальный список рассылки для обсуждения языка Go — Go Nuts.
Сообщайте об ошибках с помощью Go issue tracker.