В этом посте мы продемонстрируем разработку простого Go пакета и представим go tool, стандартный способ получения, сборки и установки пакетов и команд в Go.
go tool
требует, чтобы вы организовали свой код определенным образом.
Организация кода
- Go программисты обычно хранят весь свой Go код в одном рабочем пространстве (workspace).
- Рабочее пространство (workspace) содержит множество репозиториев систем управления версиями (например, Git).
- Каждый репозиторий содержит один или несколько пакетов (packages).
- Каждый пакет состоит из одного или нескольких исходных Go файлов в одном каталоге (папке).
- Путь к каталогу пакета определяет его путь импорта (import path).
Обратите внимание, что это отличается от других сред программирования, в которых каждый проект имеет отдельную рабочую область и рабочие области тесно связаны с репозиторием системы контроля версий.
Рабочие пространства (Workspaces)
Рабочее пространство (workspace) - это иерархия каталогов с двумя каталогами в корне:
src
содержит исходные файлы Gobin
содержит исполняемые команды
go tool
создает и устанавливает бинарные файлы в каталог bin
.
Подкаталог src
обычно содержит несколько репозиторев систем управления версиями (например, Git или Mercurial), которые отслеживают развитие одного или более исходных пакетов.
Чтобы дать вам представление о том, как рабочее пространство выглядит на практике, приведем пример:
bin/
hello # исполняемый файл
outyet # исполняемый файл
src/
github.com/golang/example/
.git/ # метаданные Git репозитория
hello/
hello.go # файл с исходным кодом
outyet/
main.go # файл с исходным кодом
main_test.go # файл с исходным кодом тестов
stringutil/
reverse.go # файл с исходным кодом пакета
reverse_test.go # файл с исходным кодом тестов
golang.org/x/image/
.git/ # метаданные Git репозитория
bmp/
reader.go # файл с исходным кодом пакета
writer.go # файл с исходным кодом пакета
... (и далее еще репозитрии и пакеты) ...
Дерево выше показывает рабочее пространство, содержащее два репозитория (example
и image
). Репозиторий example
содержит две команды (исполняемых файла) (hello
и outyet
) и одну библиотеку (stringutil
). Репозиторий image
содержит пакет bmp
и несколько других пакетов.
Типичное рабочее пространство содержит множество исходных репозиториев, содержащих множество пакетов и команд (исполняемых файлов). Большинство Go программистов хранят весь свой исходный Go код и зависимости в едином рабочем пространстве.
Обратите внимание, что символические ссылки не должны использоваться для связи файлов или каталогов с вашей рабочей областью.
Команды и библиотеки создаются из разных видов исходных пакетов.
Переменная среды GOPATH
Переменная среды GOPATH
указывает местоположение вашего рабочего окружения. По умолчанию это каталог с именем go
внутри вашего домашнего каталога, то есть $HOME/go
в Unix, и %USERPROFILE%\go
(обычно C:\Users\YourName\go
) в Windows.
Если вы хотите работать в другом месте, вам нужно будет задать в GOPATH
путь к этому каталогу. (Другой распространенной настройкой является установка GOPATH=$HOME
.)
Обратите внимание, что GOPATH
не должен быть тем же путем, что и путь вашей установки Go.
Команда go env GOPATH
печатает действующий GOPATH
; он печатает местоположение по умолчанию, если переменная окружения не установлена.
Для удобства добавьте подкаталог bin
рабочего пространства в ваш PATH
:
$ export PATH=$PATH:$(go env GOPATH)/bin
Скрипты в остальной части этого документа используют $GOPATH
вместо $(go env GOPATH)
для краткости. Чтобы скрипты работали как написано если вы не установили GOPATH, вы можете заменить $HOME/go в этих командах или выполнить:
$ export GOPATH=$(go env GOPATH)
Чтобы использовать пользовательское местоположение рабочего пространства, установите переменную среды GOPATH
.
Пути импорта (Import paths)
путь импорта (import path) - это строка, которая однозначно идентифицирует пакет. Путь импорта пакета соответствует его местоположению в рабочем пространстве или в удаленном хранилище.
Пакеты из стандартной библиотеки имеют короткие пути импорта, такие как "fmt"
и "net/http"
. Для ваших собственных пакетов вы должны выбрать базовый путь, который вряд ли столкнется с будущими дополнениями к стандартной библиотеке или другим внешним библиотекам.
Если вы храните свой код в исходном хранилище, то вам следует использовать корень этого исходного хранилища в качестве базового пути. Например, если у вас есть GitHub аккаунт на github.com/user
, это должен быть ваш базовый путь.
Обратите внимание, что вам не требуется публиковать свой код в удаленном хранилище, прежде чем вы сможете собрать его (скомпилировать). Это просто хорошая привычка организовывать свой код, как будто вы будете публиковать это когда-нибудь. На практике вы можете выбрать любое произвольное имя пути, до тех пор, пока он уникален для стандартной библиотеки и большей экосистемы Go.
Мы будем использовать github.com/user
в качестве основного пути. Создадим каталог внутри вашего рабочего пространства, в котором хранится исходный код:
$ mkdir -p $GOPATH/src/github.com/user
Ваша первая программа
Чтобы скомпилировать и запустить простую программу, сначала выберите путь к пакету (мы будем использовать github.com/user/hello
) и создайте соответствующий каталог пакета внутри вашего рабочего пространства:
$ mkdir $GOPATH/src/github.com/user/hello
Затем создайте файл с именем hello.go
внутри этого каталога, содержащий следующий Go код.
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
Теперь вы можете собрать и установить эту программу с помощью инструмента go
:
$ go install github.com/user/hello
Обратите внимание, что вы можете запустить эту команду из любой точки вашей системы. Инструмент go
находит исходный код, производя поиск пакета github.com/user/hello
внутри рабочего пространства, указанного в GOPATH
.
Вы также можете пропустить путь к пакету, если запустите go install
из каталога пакета:
$ cd $GOPATH/src/github.com/user/hello
$ go install
Эта команда создает команду hello
, создавая исполняемый бинарный файл. Затем он устанавливается в bin
каталоге рабочего пространства как hello
(или в Windows hello.exe
). В нашем примере это будет $GOPATH/bin/hello
, который $HOME/bin/hello
.
go tool
будет печатать вывод только при возникновении ошибки, поэтому если эти команды не выдают результатов, значит они выполнились успешно.
Теперь вы можете запустить программу, набрав ее полный путь в командной строке:
$ $GOPATH/bin/hello
Hello, world.
Или, поскольку вы добавили $GOPATH/bin
в свой PATH
, просто введите двоичное имя:
$ hello
Hello, world.
Если вы используете систему управления версиями, сейчас самое время инициализировать хранилище, добавьте файлы и зафиксируйте ваше первое изменение. Опять же, этот шаг необязателен: вам не нужно использовать системы контроля версий чтобы писать Go код.
$ cd $GOPATH/src/github.com/user/hello
$ git init
Initialized empty Git repository
in /home/user/work/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
1 file changed, 1 insertion(+)
create mode 100644 hello.go
Ваша первая библиотека
Давайте напишем библиотеку и будем использовать ее из программы hello
.
Опять же, первым шагом является выбор пути к пакету (мы будем использовать github.com/user/stringutil
), создаем каталог пакета:
$ mkdir $GOPATH/src/github.com/user/stringutil
Затем создаем файл с именем reverse.go
в этом каталоге.
// Пакет stringutil содержит утилитные функции
// для работы со строками.
package stringutil
// Reverse возвращает его строку аргумент
// развернутую в обратном порядке.
func Reverse(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)
}
Теперь проверьте, что пакет компилируется с помощью go build
:
$ go build github.com/user/stringutil
Или, если вы работаете в исходном каталоге пакета, просто:
$ go build
Эта команда не будет производить выходной файл. Вместо этого она сохраняет скомпилированный пакет в локальном кэше сборки.
После подтверждения сборки пакета stringutil
измените ваш оригинальный hello.go
(который находится в $GOPATH/src/github.com/user/hello
), чтобы использовать созданный пакет:
import (
"fmt"
"github.com/user/stringutil"
)
func main() {
fmt.Println(stringutil.Reverse("!oG ,olleH"))
}
Установите программу hello
:
$ go install github.com/user/hello
Запустив новую версию программы, вы должны увидеть новое, перевернутое сообщение:
$ hello
Hello, Go!
После выполнения описанных выше шагов ваше рабочее пространство должно выглядеть следующим образом:
bin/
hello # исполняемый файл команды
src/
github.com/user/
hello/
hello.go # исходный код команды
stringutil/
reverse.go # исходный код пакета
Имена пакетов
Первый оператор в исходном файле Go должен быть
package name
где name
- это имя пакета по умолчанию для импорта. (Все файлы в пакете должны использовать одно и то же name
.)
Общепринятое соглашение в Go состоит в том, что имя пакета является последним элементом пути импорта: пакет, импортированный как crypto/rot13
должно быть названо rot13
.
Исполняемые команды всегда должны использовать package main
.
Не требуется, чтобы имена пакетов были уникальными во всех пакетах, связанных в один двоичный файл, требуется только чтобы, что пути импорта (их полные имена файлов) были уникальными.
Тестирование
Go имеет легковесный фреймворк для тестирования, состоящий из go test
команды и пакета testing
.
Вы пишете тест, создавая файл с именем, заканчивающимся на _test.go
, который содержит функции с именем TestXXX
с подписью func (t * testing.T)
. Тестовый фреймворк выполняет каждую такую функцию; если функция вызывает функцию отказа, такую как t.Error
или
t.Fail
, тест считается неудачным.
Добавим тест в пакет stringutil
, создав файл $GOPATH/src/github.com/user/stringutil/reverse_test.go
, содержащий следующий Go код
package stringutil
import "testing"
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q",
c.in, got, c.want)
}
}
}
Затем запустите тест с помощью go test
:
$ go test github.com/user/stringutil
ok github.com/user/stringutil 0.165s
Как всегда, если вы запускаете go tool
из пакета каталога, вы можете пропустить путь пакета:
$ go test
ok github.com/user/stringutil 0.165s
Удаленные пакеты (Remote packages)
Путь импорта может описать, как получить исходный код пакета, используя систему контроля версий, такую как Git или Mercurial. go tool
использует это свойство для автоматической загрузки пакетов из удаленных репозиториев. Например, примеры, описанные в этом посте, также хранятся в Git-репозитории, размещенном на GitHub github.com/golang/example
. Если вы включите URL-адрес хранилища в путь импорта пакета, go get
автоматически получит, соберет и установит его:
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
Если указанный пакет отсутствует в рабочем пространстве, go get
поместит его в первое рабочее пространство, указанное в GOPATH
. (Если пакет уже существует, go get
пропускает получение удаленного пакета и ведет себя так же, как go install
.)
После ввода вышеуказанной команды go get
, дерево каталога рабочей области теперь должно выглядеть так:
bin/
hello # исполняемая команда
src/
github.com/golang/example/
.git/ # метаданные Git репозитория
hello/
hello.go # исходный файл команды
stringutil/
reverse.go # исходный файл пакета
reverse_test.go # исходный файл теста
github.com/user/
hello/
hello.go # исходный файл команды
stringutil/
reverse.go # исходный файл пакета
reverse_test.go # исходный файл теста
Команда hello
, размещенная на GitHub, зависит от пакета stringutil
в том же хранилище. Импорт в файле hello.go
использует то же соглашение о пути импорта, поэтому команда go get
может найти и установить зависимый пакет.
import "github.com/golang/example/stringutil"
Это соглашение - самый простой способ сделать ваши Go пакеты доступными для использования другими.
Читайте также:
Комментариев нет:
Отправить комментарий