Введение
В предыдущем разделе вы завершили простую программу на Go, которая содержала следующие строки кода:
package main
import "fmt"
Как понять эти две строки кода? Как эффективно использовать инструкции package и import?
В этом лабораторном занятии (LabEx) вы научитесь создавать и импортировать пакеты в Go. Это позволит вам организовать свой код в переиспользуемые модули, сделав ваши проекты на Go более поддерживаемыми и масштабируемыми.
Точки знания:
- Определение и объявление пакета
- Понимание экспортируемых (публичных) и неэкспортируемых (частных) идентификаторов
- Различные формы импорта пакетов: одиночный, групповой, точечный, с псевдонимом и анонимный импорт
Объявление и определение пакетов
Пакет в Go похож на модули в Python или библиотеки в C. Это набор файлов исходного кода, используемых для организации и повторного использования кода. Каждый файл на Go должен объявлять пакет в начале файла.
Примечание: Программа на Go должна иметь один и только один пакет с именем
main, который служит точкой входа для выполнения. Без него программа не может создать исполняемый файл.
Основные моменты:
- Экспортируемые (публичные) идентификаторы: Идентификаторы (переменные, функции, типы и т.д.), начинающиеся с заглавной буквы, доступны из других пакетов. Их можно рассматривать как публичный интерфейс вашего пакета.
- Неэкспортируемые (частные) идентификаторы: Идентификаторы, начинающиеся с строчной буквы, доступны только внутри того же пакета. Они считаются внутренними деталями реализации пакета.
- Сцепление пакета: Все файлы в одной папке должны принадлежать одному и тому же пакету. Это обеспечивает сохранение связанного кода вместе.
- Соглашения по именованию пакетов: Имена пакетов должны быть строчными, короткими и описательными, избегая подчеркиваний или заглавных букв.
Давайте создадим собственный пользовательский пакет:
Создайте папку с именем
propagandistи файлpropagandist.goвнутри нее:mkdir ~/project/propagandist touch ~/project/propagandist/propagandist.goНапишите следующий код в файле
propagandist.go:package propagandist var Shout = "I Love LabEx" // Public variable var secret = "I love the dress" // Private variable func Hit() string { return "Don't hit me, please!" }Shoutявляется публичной переменной, так как начинается с заглавной буквы. Это означает, что вы можете получить доступ к ней из других пакетов, которые импортируютpropagandist.secretявляется частной переменной, так как начинается со строчной буквы. Она может быть использована только внутри пакетаpropagandist.Hit- это публичная функция, доступная из других пакетов.
Инициализируйте модуль Go для пакета:
cd ~/project/propagandist go mod init propagandistЭта команда инициализирует новый модуль Go в директории
propagandist, который помогает управлять зависимостями пакета.
Импорт одного пакета
Для использования пакета propagandist создадим новую программу на Go. Этот шаг продемонстрирует, как импортировать и использовать один пакет в вашем коде на Go.
Создайте новый файл на Go с именем
pacExercise.goв папке проекта:touch ~/project/pacExercise.goИнициализируйте модуль Go для программы:
cd ~/project go mod init pacExerciseОбновите файл
go.mod, чтобы включить зависимость от локального пакета. Выполните следующую команду в терминале:echo "replace propagandist =>./propagandist" >> go.modВажно: Эта команда добавляет директиву
replaceв ваш файлgo.mod. Это очень важно, так как она сообщает Go, что пакетpropagandistдолжен быть взят из локальной директории./propagandist, а не пытаться скачать его из удаленного репозитория. Вы должны выполнить эту команду в терминале, которая добавит строкуreplace propagandist =>./propagandistв ваш файлgo.mod. Не пишите эту строку напрямую в файл вручную.Напишите следующий код в файле
pacExercise.go, чтобы импортировать и использовать пакетpropagandist:package main import ( "fmt" "propagandist" ) func main() { fmt.Println(propagandist.Shout) // Access the public variable }- Этот код импортирует пакет
fmtдля вывода информации и пакетpropagandist. - Затем он обращается к публичной переменной
Shoutиз пакетаpropagandistс помощьюpropagandist.Shout.
- Этот код импортирует пакет
Запустите программу:
go mod tidy go run pacExercise.goКоманда
go mod tidyгарантирует, что ваш файлgo.modобновлен с учетом любых новых зависимостей. Командаgo run pacExercise.goкомпилирует и выполняет программу.Ожидаемый вывод:
I Love LabEx
Групповой импорт
При импорте нескольких пакетов можно использовать групповой импорт для улучшения читаемости и организации кода. Это вопрос стиля и не влияет на функциональность вашего кода.
Измените файл
pacExercise.go, чтобы использовать групповой импорт:package main import ( "fmt" "propagandist" ) func main() { fmt.Println(propagandist.Shout) }В приведенном выше фрагменте кода пакеты
fmtиpropagandistимпортируются внутри одного блокаimport, заключенного в скобки. Это упрощает чтение и управление импортом нескольких пакетов. Это точно то же, что и в предыдущем примере, и показывает, как использовать синтаксис группового импорта.Запустите программу, чтобы убедиться, что она по-прежнему работает:
go run pacExercise.goПрограмма должна выполниться без ошибок и выдать тот же результат, что и раньше.
Точечный импорт
При использовании точкового импорта можно опустить префикс имени пакета при вызове его функций или переменных. Это часто не рекомендуется в пользу явных имен пакетов, так как это может привести к конфликтам пространств имен и снизить читаемость. Однако полезно знать, что это такое.
Измените файл
pacExercise.go, чтобы использовать точковый импорт для пакетаfmt:package main import. "fmt" import "propagandist" func main() { Println(propagandist.Shout) // No `fmt.` prefix needed }- Здесь
import. "fmt"означает, что вы можете использовать функции и переменные из пакетаfmtнапрямую, без префиксаfmt.. - Например, вы используете
Printlnвместоfmt.Println.
- Здесь
Запустите программу:
go run pacExercise.goОжидаемый вывод:
I Love LabEx
Импорт с псевдонимом
Вы можете назначить псевдоним импортируемому пакету для ясности или чтобы избежать конфликтов, когда два пакета имеют похожие имена. Это помогает сделать ваш код более читаемым и управлять коллизиями пространств имен.
Измените файл
pacExercise.go, чтобы назначить псевдонимioпакетуfmt:package main import io "fmt" import "propagandist" func main() { io.Println(propagandist.Shout) // Use the alias `io` instead of `fmt` }import io "fmt"создает псевдонимioдля пакетаfmt.- Теперь вы используете
io.Printlnвместоfmt.Println.
Запустите программу:
go run pacExercise.go
Анонимный импорт
Анонимный импорт используется для импорта пакета ради его побочных эффектов, таких как выполнение его функции init(), без необходимости напрямую ссылаться на его экспортируемые идентификаторы. Это полезно для пакетов, которые регистрируют драйверы или выполняют другие задачи инициализации.
Измените файл
pacExercise.go, чтобы включить анонимный импорт пакетаtime:package main import ( "fmt" "propagandist" _ "time" // Anonymous import ) func main() { fmt.Println(propagandist.Shout) }import _ "time"- это анонимный импорт. Подчеркивание_используется как пустой идентификатор, сообщающий компилятору, что вы импортируете пакет ради его побочных эффектов и не будете напрямую ссылаться на его содержимое в своем коде.- Функция
init()пакетаtimeбудет выполнена при запуске этой программы. Пакетtimeне имеет каких - то особых видимых побочных эффектов здесь, однако многие пакеты используют этот подход для регистрации драйверов баз данных или настройки конфигурации.
Запустите программу:
go run pacExercise.goОжидаемый вывод:
I Love LabEx
Резюме
В этом практическом занятии вы узнали:
- Как создавать и определять пользовательские пакеты в Go, инкапсулируя повторно используемый код.
- Разницу между публичными (экспортируемыми) и приватными (неэкспортируемыми) идентификаторами и то, как они влияют на доступность.
- Различные способы импорта пакетов и их области применения:
- Импорт одного пакета за раз: Импортирование по одному пакету за раз.
- Групповой импорт: Импортирование нескольких пакетов в одном блоке для лучшей организации.
- Точковый импорт: Импортирование пакета и использование его идентификаторов напрямую без префикса имени пакета. (Используйте с осторожностью)
- Импорт с псевдонимом: Переименование импортированных пакетов для лучшей читаемости или избежания конфликтов имен.
- Анонимный импорт: Импортирование пакета только ради его побочных эффектов, таких как инициализация.
- Роль функции
init()в пакетах и то, как анонимный импорт может вызвать ее выполнение.
Завершив это практическое занятие, вы теперь можете эффективно структурировать и управлять проектами на Go с использованием пакетов. Вы можете создавать повторно используемые модули, контролировать доступ к идентификаторам и лучше организовать свой код, что приведет к созданию более поддерживаемых и масштабируемых приложений на Go.
Summary
In this lab, you learned:
- How to create and define custom packages in Go, encapsulating reusable code.
- The difference between public (exported) and private (unexported) identifiers and how they impact accessibility.
- Various ways to import packages, each with its use case:
- Single-item import: Importing one package at a time.
- Grouped import: Importing multiple packages in a single block for better organization.
- Dot import: Importing a package and using its identifiers directly without the package name prefix. (Use with caution)
- Alias import: Renaming imported packages for better readability or to avoid naming conflicts.
- Anonymous import: Importing a package solely for its side effects, such as initialization.
- The role of the
init()function in packages and how anonymous imports can trigger its execution. - The detailed workings of Go's initialization process, including:
- How package-level variables are initialized before
init()functions - The guaranteed execution order of
init()functions across dependent packages - How multiple
init()functions work within a package - The complete initialization flow from dependent packages to the main function
- How package-level variables are initialized before
By completing this lab, you are now equipped to structure and manage Go projects using packages effectively. You can create reusable modules, control access to identifiers, better organize your code, and understand the initialization process, leading to more maintainable and scalable Go applications.



