Сведения о пакетах

Завершено

Пакеты в Go подобны библиотекам или модулям в других языках программирования. Можно упаковать код и использовать его в другом месте. Исходный код пакета может распространяться в нескольких файлах .go. На данный момент мы написали пакет main и создали несколько ссылок на другие собственные пакеты.

В этом разделе вы узнаете, что такое пакет. Вы также узнаете, как его создать и как использовать внешние пакеты.

Основной пакет

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

Другими словами, при использовании пакета main программа создаст автономный исполняемый файл. Но если программа входит в пакет, отличный от main, Go не создаст двоичный файл. Он создает архивный файл пакета (файл с расширением .a ).

В Go имена пакетов соответствуют соглашению. В имени пакета используется последняя часть его пути импорта. Например, библиотека Go Standard содержит пакет с именем math/cmplx, который предоставляет полезный код для работы с комплексными числами. Путь импорта этого пакета — math/cmplx. Он импортируется следующим образом:

import "math/cmplx"

Для ссылки на объекты в пакете используется имя пакета, cmplx, например:

cmplx.Inf()

Давайте создадим пакет.

Создание пакета

Создайте в каталоге calculator новый каталог с именем $GOPATH/src. Создайте файл с именем sum.go. Структура каталога должна выглядеть так:

src/
  calculator/
    sum.go

Инициализируйте файл sum.go именем пакета:

package calculator

Теперь можно приступить к написанию функций и переменных для пакета. В отличие от других языков программирования, Go не предоставляет ключевые слова public или private, чтобы указать, можно ли вызывать переменную или функцию извне или изнутри пакета. Но Go руководствуется двумя простыми правилами:

  • если элемент должен быть частным, его имя должно начинаться со строчной буквы;
  • если элемент должен быть общедоступным, его имя должно начинаться с прописной буквы.

Поэтому добавим следующий код в создаваемый пакет калькулятора:

package calculator

var logMessage = "[LOG]"

// Version of the calculator
var Version = "1.0"

func internalSum(number int) int {
    return number - 1
}

// Sum two integer numbers
func Sum(number1, number2 int) int {
    return number1 + number2
}

Рассмотрим несколько моментов в этом коде.

  • Переменная logMessage может быть вызвана только из пакета.
  • Переменная Version может быть доступна из любого места. Для описания назначения этой переменной рекомендуется включить комментарий. (Это описание будет полезно всем, кто будет использовать этот пакет.)
  • Функция internalSum может быть вызвана только из пакета.
  • Функция Sum может быть доступна из любого места. Для описания назначения этой функции рекомендуется включить комментарий.

Чтобы проверить, что все работает, выполните команду go build в каталоге calculator. В этом случае обратите внимание, что исполняемый файл не создается.

Создание модуля

Вы поместили в пакет функцию калькулятора. Теперь поместим этот пакет в модуль. Модули Go обычно содержат пакеты, предлагающие связанные функции. Модуль пакета также определяет контекст, необходимый Go для выполнения объединенного кода. Эти контекстные сведения содержат версию Go, для которой предназначен код.

Кроме того, с помощью модулей другие разработчики могут ссылаться на определенные версии кода и упростить работу с зависимостями. Другое преимущество заключается в том, что исходный код программы необязательно должен находиться в каталоге $GOPATH/src. Снятие этого ограничения повышает удобство работы с различными версиями пакетов в разных проектах одновременно.

Итак, чтобы создать модуль для пакета calculator, выполните следующую команду в корневом каталоге ($GOPATH/src/calculator):

go mod init github.com/myuser/calculator

После выполнения этой команды github.com/myuser/calculator станет именем модуля. Вы будете ссылаться на это имя в других программах. Команда также создает файл с именем go.mod. Наконец, каталог дерева теперь выглядит как следующий каталог:

src/
  calculator/
    go.mod
    sum.go

Содержимое файла go.mod должно быть похоже на приведенный ниже код. (Версия Go может быть другой.)

module github.com/myuser/calculator

go 1.14

Чтобы ссылаться на пакет calculator в других программах, его необходимо импортировать, используя имя модуля. В этом случае используется имя github.com/myuser/calculator. Теперь рассмотрим пример использования этого пакета.

Примечание.

Исторически управление зависимостями в Go было непростой задачей. Над системой управления зависимостями все еще ведется работа. Дополнительные сведения о модулях см. в серии записей, опубликованных в блоге, посвященном Go.

Ссылка на локальный пакет (модуль)

Теперь давайте поработаем с пакетом. Мы будем использовать уже знакомый нам пример приложения. На этот раз вместо функции sum в пакете main воспользуемся функцией, созданной ранее в пакете calculator.

Теперь древовидная структура файла должна выглядеть следующим образом:

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    main.go

Для файла $GOPATH/src/helloworld/main.go будет использоваться следующий код:

package main

import (
  "fmt"
  "github.com/myuser/calculator"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
}

Обратите внимание, что оператор import использует имя созданного пакета: calculator. Чтобы вызвать функцию Sum из этого пакета, необходимо указать имя пакета, как в calculator.Sum. В итоге у вас также есть доступ к переменной Version. Ее можно назвать calculator.Version.

Если вы попытаетесь запустить программу именно в этот момент, она не будет работать. Необходимо сообщить Go о том, что вы используете модули для ссылки на другие пакеты. Для этого выполните следующую команду в каталоге $GOPATH/src/helloworld:

go mod init helloworld

В предыдущей команде helloworld имя проекта. Эта команда создает файл go.mod, поэтому теперь каталог дерева выглядит следующим образом:

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    go.mod
    main.go

Откройте файл go.mod. Его содержимое должно выглядеть подобно приведенному ниже коду: (Версия Go может быть другой.)

module helloworld

go 1.14

Так как вы ссылаетесь на локальную копию модуля, необходимо сообщить Go о том, что вы не хотите использовать удаленное расположение. Поэтому необходимо вручную изменить файл go.mod для включения ссылки, как показано ниже:

module helloworld

go 1.14

require github.com/myuser/calculator v0.0.0

replace github.com/myuser/calculator => ../calculator

Ключевое слово replace указывает, что вместо удаленного расположения модуля используется локальный каталог. В этом случае расположением будет просто ../calculator, поскольку программы helloworld и calculator находятся в $GOPATH/src. Если источник модуля находится в другом расположении, укажите здесь локальный путь.

Запустите программу с помощью следующей команды:

go run main.go

Выходные данные должны выглядеть следующим образом:

8
Version:  1.0

Задание 1

Что произойдет при попытке вызова переменной logMessage или функции internalSum из пакета calculator в главном приложении? Все получится? Попробуйте сами!

Решение проблемы:

package main

import (
 "fmt"
 "github.com/myuser/calculator"
)

func main() {
    total := calculator.internalSum(5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.logMessage)
}

Публикация пакета

Опубликовать пакет Go довольно просто. Необходимо просто сделать исходный код пакета общедоступным. Большинство разработчиков используют GitHub, чтобы сделать пакеты доступными для общественности, поэтому иногда вы найдете ссылки на github.com инструкции импорта.

Например, чтобы опубликовать пакет calculator в учетную запись GitHub, необходимо создать репозиторий с именем calculator. URL-адрес должен выглядеть примерно так:

https://github.com/myuser/calculator

Вы будете назначать версии пакетам, маркируя свой репозиторий следующим образом:

git tag v0.1.0
git push origin v0.1.0

Разработчики, желающие использовать ваш пакет (в том числе вы сами), должны ссылаться на него следующим образом:

import "github.com/myuser/calculator"

Давайте рассмотрим, как ссылаться на сторонние пакеты, более подробно.

Ссылки на внешние (сторонние) пакеты

Иногда в программах требуются ссылки на пакеты, написанные другими разработчиками. Как правило, эти пакеты доступны на сайте GitHub. Приведенные далее инструкции по ссылкам на сторонние пакеты работают независимо от того, что именно вы разрабатываете: пакет (пакет, отличный от main) или автономную программу (пакет main).

Добавим ссылку на пакет rsc.io/quote:

package main

import (
    "fmt"
    "github.com/myuser/calculator"
    "rsc.io/quote"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
    fmt.Println(quote.Hello())
}

Если вы используете Visual Studio Code, файл go.mod обновится при сохранении. Теперь выглядит следующим образом:

module helloworld

go 1.14

require (
    github.com/myuser/calculator v0.0.0
    rsc.io/quote v1.5.2
)

replace github.com/myuser/calculator => ../calculator

Обратите внимание, каким образом rsc.io/quote ссылается на определенную версию пакета. Если нужно обновить зависимости программы, потребуется изменить ее версию.

Запустите программу еще раз с помощью следующей команды:

go run main.go

Выходные данные должны выглядеть так:

8
Version:  1.0
Hello, world.

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