Основы программирования на языке Go

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

1. Введение в Go: установка окружения, переменные, базовые типы и управляющие конструкции

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

Добро пожаловать в курс «Основы программирования на языке Go». Это первая статья, с которой начнется ваше погружение в один из самых востребованных и эффективных языков программирования современности. Мы пройдем путь от настройки рабочего места до написания первых алгоритмов.

Что такое Go и почему он популярен?

Go (часто называемый Golang) — это компилируемый, многопоточный язык программирования со статической типизацией, разработанный внутри компании Google. Его создатели — легенды компьютерных наук: Роб Пайк, Кен Томпсон и Роберт Гризмер. Язык был представлен общественности в 2009 году.

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

!Иллюстрация того, как исходный код Go превращается в машинный код для разных платформ.

Ключевые преимущества: * Скорость: Go компилируется в машинный код, что делает его очень быстрым. * Простота: Синтаксис лаконичен, ключевых слов всего 25. * Параллелизм: Встроенные механизмы для работы с многопоточностью (горутины и каналы) являются визитной карточкой языка. * Богатая стандартная библиотека: «Батарейки в комплекте» — мощные инструменты для работы с сетью и текстом доступны сразу.

Установка окружения

Прежде чем писать код, необходимо подготовить инструменты. Процесс установки Go максимально упрощен.

Шаг 1: Загрузка Go

Перейдите на официальный сайт go.dev и скачайте дистрибутив для вашей операционной системы (Windows, macOS или Linux). Следуйте инструкциям установщика.

Шаг 2: Проверка установки

Откройте терминал (или командную строку) и введите команду:

Если вы видите вывод, похожий на go version go1.21.0 darwin/arm64, значит, установка прошла успешно.

Шаг 3: Выбор редактора кода

Хотя писать код можно и в «Блокноте», для комфортной работы рекомендуются современные IDE:

  • Visual Studio Code: Бесплатный, легкий и мощный редактор. Обязательно установите расширение «Go» от команды Go Team.
  • GoLand: Полноценная IDE от JetBrains (платная, но есть пробный период). Идеальна для крупных проектов.
  • Ваша первая программа: Hello, World!

    По традиции начнем с программы, которая выводит приветствие на экран. Создайте файл с именем main.go и напишите в нем следующий код:

    Разберем структуру программы построчно:

  • package main: Эта строка объявляет, что файл принадлежит пакету main. Именно с этого пакета начинается выполнение любой исполняемой программы в Go.
  • import "fmt": Мы подключаем (импортируем) пакет fmt, который отвечает за форматированный ввод и вывод данных (аналог printf в C или print в Python).
  • func main() { ... }: Объявление главной функции. Программа начинает свою работу с кода внутри фигурных скобок этой функции.
  • Чтобы запустить программу, откройте терминал в папке с файлом и введите:

    Переменные и константы

    Go — язык со статической типизацией. Это означает, что тип переменной известен на этапе компиляции, что помогает избежать множества ошибок.

    !Визуальная метафора переменных как контейнеров для хранения данных определенного типа.

    Объявление переменных

    Существует два основных способа создания переменных.

    1. Полная форма (через ключевое слово var): Используется, когда нужно явно указать тип или объявить переменную без начального значения.

    2. Краткая форма (только внутри функций): Используется оператор :=. Компилятор сам определит тип переменной на основе значения справа.

    > Важно: В Go нельзя объявить переменную и не использовать её. Если переменная объявлена, но не используется, компилятор выдаст ошибку. Это сделано для чистоты кода.

    Константы

    Константы объявляются с помощью ключевого слова const. Их значение нельзя изменить после объявления.

    Базовые типы данных

    В Go есть несколько фундаментальных типов данных, на которых строятся более сложные структуры.

    Целые числа (Integers)

    Самые используемые типы — это int (зависит от разрядности системы, 32 или 64 бита) и int64.

    Если нам нужно вычислить диапазон значений для -битного знакового целого числа, мы используем формулу:

    Где — количество бит, а — допустимое значение переменной. Например, для 8-битного числа (int8) диапазон будет от -128 до 127.

    Числа с плавающей точкой (Floats)

    Для дробных чисел используются float32 и float64. По умолчанию при кратком объявлении (:=) используется float64, так как он обеспечивает большую точность.

    Булев тип (Boolean)

    Тип bool может принимать только два значения: true (истина) или false (ложь). Часто используется в условных операторах.

    Строки (Strings)

    Строки в Go — это неизменяемые последовательности байтов. Они заключаются в двойные кавычки.

    Нулевые значения (Zero Values)

    Особенность Go в том, что переменные всегда инициализируются. Если вы не присвоили значение явно, переменная получит «нулевое значение» для своего типа: * 0 для чисел * false для bool * "" (пустая строка) для string * nil для указателей и ссылочных типов

    Управляющие конструкции

    Логика программы строится на ветвлениях и циклах. Go предлагает минималистичный, но мощный набор инструментов.

    Условный оператор if

    Синтаксис if в Go похож на C или Java, но круглые скобки вокруг условия не нужны, а фигурные скобки обязательны.

    Также if позволяет выполнить короткую инструкцию перед проверкой условия:

    Цикл for

    В Go есть только один цикл — for. Но он настолько гибок, что заменяет собой while и do-while из других языков.

    1. Классический цикл:

    2. Цикл типа while (только условие):

    3. Бесконечный цикл:

    Оператор switch

    switch используется для выбора одного из множества вариантов. В отличие от C++, в Go не нужно писать break в конце каждого кейса — выход происходит автоматически после выполнения совпавшего блока.

    Заключение

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

    В следующей статье мы углубимся в более сложные структуры данных: массивы, срезы (slices) и карты (maps), которые делают работу с коллекциями данных в Go невероятно удобной.

    2. Работа с данными: массивы, слайсы, карты (maps) и структуры

    Работа с данными: массивы, слайсы, карты (maps) и структуры

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

    В этой статье мы разберем четыре кита, на которых держится работа с данными в Go: массивы, слайсы (срезы), карты (maps) и структуры. Понимание этих инструментов — ключ к написанию эффективного кода.

    Массивы (Arrays)

    Массив — это нумерованная последовательность элементов одного типа, имеющая фиксированную длину. Главное, что нужно запомнить: размер массива является частью его типа.

    Это означает, что [5]int и [10]int — это совершенно разные типы данных, и вы не сможете присвоить один другому.

    Объявление и инициализация

    Если вы хотите, чтобы компилятор сам посчитал количество элементов, используйте троеточие:

    Почему массивы редко используют напрямую?

    Из-за фиксированного размера массивы неудобны для большинства задач. Если вы создали массив на 10 элементов, а вам нужно добавить 11-й, вам придется создавать новый массив большего размера и копировать туда все данные вручную. В Go массивы чаще служат «строительными блоками» для более гибкой структуры — слайсов.

    Слайсы (Slices)

    Слайс (или срез) — это, пожалуй, самая часто используемая структура данных в Go. В отличие от массивов, слайсы имеют динамический размер. Вы можете добавлять в них элементы, и они будут расти автоматически.

    !Слайс — это «окно» в базовый массив, имеющее длину и вместимость.

    Анатомия слайса

    Технически слайс — это легковесная структура, которая содержит три поля:

  • Pointer — указатель на первый элемент внутри базового массива.
  • Length (len) — количество элементов, которые содержит слайс сейчас.
  • Capacity (cap) — количество элементов, которые поместятся в базовый массив до того, как потребуется выделить новую память.
  • Создание слайсов

    Самый простой способ создать слайс — опустить размер в квадратных скобках:

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

    Добавление элементов

    Для добавления элементов используется встроенная функция append. Она возвращает новый слайс, поэтому результат нужно обязательно присвоить переменной.

    Когда место в базовом массиве заканчивается (length достигает capacity), Go автоматически создает новый, больший массив, копирует туда данные и возвращает обновленный слайс. Обычно новая вместимость рассчитывается по формуле удвоения (для небольших слайсов):

    где — новая вместимость (capacity), а — текущая вместимость.

    Срезы слайсов

    Вы можете получить часть слайса, используя оператор двоеточия low:high. Это создает новый вид на тот же массив данных (копирования не происходит).

    Карты (Maps)

    Карта (в других языках известная как хэш-таблица, словарь или ассоциативный массив) — это неупорядоченная коллекция пар «ключ-значение». Это идеальный инструмент для быстрого поиска данных.

    !Карта связывает уникальные ключи с конкретными значениями.

    Объявление и инициализация

    Работа с элементами

    Получение значения по ключу:

    Если ключа не существует, карта вернет нулевое значение для типа данных значения (например, 0 для int). Это может привести к путанице: цена равна 0 или товара нет в списке?

    Для проверки существования ключа используется идиома «comma ok»:

    Для удаления элемента используется функция delete:

    > Важно: Порядок обхода карты в цикле for range в Go случайный. Не полагайтесь на то, что элементы будут выводиться в том же порядке, в котором вы их добавили.

    Структуры (Structs)

    Если массивы и карты хранят данные одного типа, то структуры позволяют объединять данные разных типов в единую сущность. Это основа объектно-ориентированного подхода в Go.

    Определение структуры

    Структура — это чертеж (blueprint) вашего объекта.

    Создание экземпляров

    Доступ к полям

    Доступ осуществляется через точку:

    Вложенные структуры и анонимные поля

    Структуры могут содержать другие структуры. Это позволяет строить сложные иерархии данных.

    Итерация по коллекциям

    Для перебора всех рассмотренных коллекций используется ключевое слово range.

    Для слайсов и массивов:

    Для карт:

    Если вам не нужен индекс или ключ, используйте символ подчеркивания _ (blank identifier), чтобы игнорировать переменную.

    Заключение

    Мы рассмотрели основные инструменты для хранения и структурирования данных в Go: * Массивы для фиксированных последовательностей. * Слайсы для динамических списков (используются в 99% случаев). * Карты для быстрого поиска по ключу. * Структуры для создания собственных типов данных, описывающих реальные объекты.

    Владение этими структурами позволит вам моделировать любые данные в ваших программах. В следующей статье мы перейдем к тому, как заставить эти данные работать — мы изучим функции.

    3. Архитектура кода: функции, методы, интерфейсы и обработка ошибок

    Архитектура кода: функции, методы, интерфейсы и обработка ошибок

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

    Функции: основа логики

    Функция — это независимый блок кода, который выполняет определенную задачу. В Go функции являются «гражданами первого класса»: их можно присваивать переменным, передавать как аргументы и возвращать из других функций.

    Объявление функции

    Базовый синтаксис выглядит так:

    Если параметры имеют один и тот же тип, его можно указать один раз:

    Множественные возвращаемые значения

    Одной из киллер-фич Go является возможность возвращать несколько значений из одной функции. Это часто используется для возврата результата и ошибки одновременно.

    Именованные возвращаемые значения

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

    Вариативные функции

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

    Методы: поведение данных

    Если функция — это абстрактное действие, то метод — это действие, привязанное к конкретному типу данных (обычно к структуре). Это позволяет реализовать объектно-ориентированный подход.

    Receiver (Получатель)

    Метод объявляется так же, как функция, но перед именем метода указывается получатель (receiver) в круглых скобках.

    Теперь мы можем вызывать этот метод через точку:

    Value Receiver vs Pointer Receiver

    Это критически важный момент в Go. Существует два типа получателей:

  • Value Receiver (по значению): func (c Circle). В метод передается копия структуры. Изменения внутри метода не повлияют на оригинальный объект.
  • Pointer Receiver (по указателю): func (c *Circle). В метод передается ссылка на объект. Изменения сохранятся.
  • !Иллюстрация разницы между передачей по значению (работа с копией) и по указателю (работа с оригиналом).

    Пример изменения состояния:

    Используйте указатели, если метод должен менять состояние структуры или если структура слишком большая, чтобы ее постоянно копировать.

    Интерфейсы: гибкость и полиморфизм

    Интерфейсы в Go — это контракты. Они описывают поведение (набор методов), но не реализацию. Если тип имеет все методы, описанные в интерфейсе, он автоматически реализует этот интерфейс. Это называется «утиная типизация» (Duck typing).

    > «Если это выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, и есть утка».

    Объявление интерфейса

    Представим, что у нас есть разные фигуры, и мы хотим вычислять их площадь.

    Теперь любой тип, у которого есть методы Area() и Perimeter(), считается типом Shape.

    Реализация

    Нам не нужно писать implements Shape. Достаточно просто реализовать методы.

    Теперь мы можем написать функцию, которая принимает интерфейс:

    Эта функция будет работать и для Circle, и для Rectangle, и для любой другой фигуры, которую вы придумаете в будущем.

    Пустой интерфейс

    Интерфейс interface{} (или any в новых версиях Go) не содержит методов. Это означает, что любой тип реализует пустой интерфейс. Он используется, когда функция должна принимать данные абсолютно любого типа (аналог Object в Java или void* в C).

    Обработка ошибок

    В Go нет исключений (try-catch). Ошибки — это обычные значения, которые возвращаются из функций. Это заставляет программиста явно обрабатывать каждую возможную проблему, что делает код более надежным.

    Тип error

    Встроенный интерфейс error выглядит так:

    Паттерн проверки ошибок

    Стандартный способ работы с ошибками:

    Defer, Panic и Recover

    Хотя исключений нет, в Go есть механизм для работы с паническими ситуациями и очисткой ресурсов.

    1. Defer (Отложенный вызов) Оператор defer откладывает выполнение функции до момента выхода из окружающей функции. Это идеально подходит для закрытия файлов или разблокировки мьютексов.

    Аргументы функции вычисляются сразу, но вызов происходит при выходе. Если defer несколько, они выполняются в порядке LIFO (Last In, First Out — последним пришел, первым вышел).

    2. Panic (Паника) panic останавливает обычное выполнение программы. Используется только для критических ошибок, которые программа не может исправить (например, нарушение целостности памяти).

    3. Recover (Восстановление) recover позволяет перехватить панику и восстановить управление. Работает только внутри defer.

    Математический пример: Расчет энергии

    Чтобы закрепить использование функций и типов, рассмотрим формулу кинетической энергии:

    Где — кинетическая энергия, — масса тела, а — скорость тела.

    Реализуем это в коде:

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

    Заключение

    Мы рассмотрели архитектурный скелет Go: * Функции инкапсулируют логику. * Методы связывают логику с данными. * Интерфейсы позволяют писать обобщенный код. * Ошибки обрабатываются явно, что повышает надежность.

    Эти инструменты позволяют строить сложные, но понятные системы. В следующей статье мы перейдем к самой захватывающей теме Go — конкурентности и многопоточности (горутины и каналы).

    4. Конкурентность в Go: горутины, каналы и примитивы синхронизации

    Конкурентность в Go: горутины, каналы и примитивы синхронизации

    В предыдущих статьях мы научились строить логику программ, используя функции, методы и интерфейсы. Однако до сих пор наши программы выполнялись последовательно: строка за строкой, инструкция за инструкцией. В современном мире, где процессоры имеют десятки ядер, такой подход неэффективен.

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

    Конкурентность против Параллелизма

    Прежде чем писать код, важно понять разницу между этими понятиями. Роб Пайк, один из создателей Go, сформулировал это так:

    > «Конкурентность — это о структуре программы. Параллелизм — это о том, как программа выполняется».

    * Конкурентность (Concurrency): Способность программы иметь дело с несколькими вещами одновременно (разбиение задачи на независимые части). * Параллелизм (Parallelism): Физическое выполнение нескольких задач в один и тот же момент времени (требует многоядерного процессора).

    Go предоставляет инструменты для написания конкурентного кода, который среда выполнения (Runtime) автоматически распараллеливает на доступные ядра процессора.

    Горутины (Goroutines)

    Горутина — это функция, которая выполняется конкурентно с другими функциями. Можно представить их как очень легкие потоки.

    Если обычный поток операционной системы (OS Thread) занимает около 1-2 МБ памяти, то горутина начинает всего с 2 КБ. Это позволяет запускать сотни тысяч горутин на одной машине без нехватки памяти.

    Для оценки эффективности использования памяти можно использовать простую формулу:

    Где — общий объем потребляемой памяти, — количество запущенных горутин, а — начальный размер стека одной горутины (обычно 2 КБ). Например, 100 000 горутин займут всего около 200 МБ оперативной памяти, что ничтожно мало для современных серверов.

    !Визуальное сравнение легковесности горутин по сравнению с системными потоками.

    Запуск горутины

    Чтобы запустить функцию в отдельной горутине, достаточно добавить ключевое слово go перед вызовом функции.

    Важный нюанс: Функция main — это тоже горутина. Если main завершает работу, программа закрывается немедленно, убивая все остальные запущенные горутины, даже если они не успели выполниться. Именно поэтому в примере выше мы добавили time.Sleep.

    Синхронизация с WaitGroup

    Использовать time.Sleep для ожидания завершения горутин — плохая практика, так как мы не знаем точно, сколько времени займет выполнение. Правильный способ — использовать примитив синхронизации WaitGroup из пакета sync.

    Он работает как счетчик:

  • Мы увеличиваем счетчик, когда запускаем горутину.
  • Горутина уменьшает счетчик, когда заканчивает работу.
  • main блокируется и ждет, пока счетчик не станет равен нулю.
  • Каналы (Channels)

    Горутины работают отлично, но как им обмениваться данными? Здесь вступает в силу философия Go:

    > «Не общайтесь, используя общую память; используйте общую память, общаясь».

    Каналы — это трубы, по которым горутины могут отправлять и принимать значения. Каналы типизированы: канал chan int может передавать только целые числа.

    !Метафора канала как трубы для передачи данных между горутинами.

    Создание и использование

    Блокировка

    По умолчанию каналы небуферизированные. Это означает: * Отправка chan <- val блокирует горутину, пока кто-то не прочитает данные. * Чтение <- chan блокирует горутину, пока кто-то не отправит данные.

    Это свойство позволяет использовать каналы не только для передачи данных, но и для синхронизации моментов выполнения.

    Буферизированные каналы

    Можно создать канал с емкостью. Он не заблокирует отправителя, пока в буфере есть место.

    Закрытие каналов и range

    Отправитель может закрыть канал, чтобы показать, что данных больше не будет.

    Получатель может проверить, закрыт ли канал:

    Самый удобный способ читать из канала до его закрытия — цикл for range:

    Конструкция Select

    Оператор select позволяет горутине ожидать операции сразу с несколькими каналами. Это похоже на switch, но для каналов.

    select выберет тот кейс, который готов к выполнению первым. Если готовы несколько — выберет случайный.

    Состояние гонки и Мьютексы (Mutex)

    Иногда нам все же приходится работать с общей памятью (например, счетчиками или кэшами). Если несколько горутин одновременно пытаются изменить одну переменную, возникает состояние гонки (Race Condition). Результат такой программы непредсказуем.

    Для защиты критических секций кода используется Mutex (Mutual Exclusion — взаимное исключение).

    Когда одна горутина вызывает Lock(), все остальные, пытающиеся вызвать Lock(), будут ждать, пока первая не вызовет Unlock().

    Заключение

    Конкурентность в Go — это не просто библиотека, это часть языка. Мы рассмотрели: * Горутины для запуска независимых задач. * WaitGroup для ожидания завершения группы задач. * Каналы для безопасной передачи данных и синхронизации. * Select для управления множеством каналов. * Мьютексы для защиты общей памяти.

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

    5. Экосистема Go: модули, тестирование и работа со стандартной библиотекой

    Экосистема Go: модули, тестирование и работа со стандартной библиотекой

    Мы прошли долгий путь: от написания первой программы «Hello, World!» до создания конкурентных приложений с использованием горутин и каналов. Теперь, когда вы владеете синтаксисом и ключевыми концепциями языка, пришло время поговорить о том, что делает Go по-настоящему готовым к промышленной разработке.

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

  • Go Modules: Как управлять зависимостями и версиями библиотек.
  • Тестирование: Как писать надежный код, используя встроенные инструменты.
  • Стандартная библиотека: Обзор мощных пакетов, которые идут «в комплекте».
  • Управление зависимостями: Go Modules

    В ранних версиях Go управление внешними библиотеками было сложной задачей, завязанной на переменную окружения GOPATH. Однако с версии 1.11 (и окончательно с 1.13) стандартом стали Go Modules.

    Модуль — это коллекция пакетов Go, которые хранятся в дереве файлов с файлом go.mod в корне. Этот файл определяет путь модуля (обычно это URL репозитория) и его зависимости.

    !Визуализация того, как файл go.mod связывает ваш проект с внешними библиотеками.

    Инициализация модуля

    Чтобы начать новый проект, создайте папку и выполните команду инициализации:

    Эта команда создаст файл go.mod. Изначально он содержит только имя вашего модуля и версию Go.

    Добавление зависимостей

    Предположим, вы хотите использовать популярную библиотеку для логирования zap от Uber. Вам не нужно скачивать её вручную. Просто импортируйте её в коде:

    Затем выполните команду:

    Эта команда — ваш лучший друг. Она делает две вещи:

  • Скачивает все библиотеки, которые вы импортировали в коде, и добавляет их в go.mod.
  • Удаляет из go.mod библиотеки, которые вы больше не используете.
  • Также появится файл go.sum. Он содержит криптографические хеши содержимого конкретных версий модулей. Это гарантирует, что код зависимостей, который скачают ваши коллеги, будет байт-в-байт совпадать с тем, что использовали вы.

    Тестирование в Go

    Создатели Go сделали тестирование частью языка, а не сторонней надстройкой. Вам не нужно устанавливать JUnit, PyTest или Mocha. Все необходимое уже есть в пакете testing.

    Правила написания тестов

  • Файлы с тестами должны называться с суффиксом _test.go (например, math_test.go для тестирования math.go).
  • Тестовые функции должны начинаться со слова Test (например, TestSum).
  • Функция принимает один аргумент: t *testing.T.
  • Рассмотрим простую функцию сложения:

    Напишем для неё тест:

    Запуск тестов выполняется командой:

    Табличные тесты (Table-Driven Tests)

    В Go принят идиоматичный подход к тестированию, называемый табличными тестами. Вместо того чтобы писать отдельные функции для каждого кейса (как TestAddPositive, TestAddNegative), мы создаем структуру данных с входными параметрами и ожидаемым результатом, а затем проходим по ней в цикле.

    Такой подход позволяет легко добавлять новые сценарии проверки, просто добавляя строку в слайс tests.

    Покрытие кода тестами (Code Coverage)

    Важной метрикой качества является покрытие кода (coverage). Оно показывает, какой процент строк вашего кода выполняется во время тестов.

    Математически покрытие можно выразить формулой:

    Где: * — процент покрытия кода. * — количество строк кода, выполненных в процессе тестирования. * — общее количество исполняемых строк в программе.

    Чтобы узнать покрытие, используйте флаг -cover:

    Стандартная библиотека: «Батарейки в комплекте»

    Философия Go подразумевает богатую стандартную библиотеку, которая позволяет решать большинство задач без подключения сторонних зависимостей. Рассмотрим несколько ключевых пакетов.

    net/http: Веб-сервер за 5 строк

    Go рожден для веба. Пакет net/http позволяет создать производительный веб-сервер без использования фреймворков вроде Django или Spring.

    Запустив этот код, вы получите рабочий веб-сервер на порту 8080. Этот пакет также включает в себя мощный HTTP-клиент для выполнения запросов к другим сервисам.

    encoding/json: Работа с данными

    В современном мире данные часто передаются в формате JSON. Пакет encoding/json позволяет легко преобразовывать структуры Go в JSON (маршалинг) и обратно (анмаршалинг).

    Для управления тем, как поля структуры превращаются в поля JSON, используются специальные теги:

    os и io: Работа с системой

    Пакеты os и io предоставляют интерфейс к операционной системе. Чтение файлов, работа с переменными окружения, запуск процессов — все это делается здесь.

    Пример чтения файла:

    Инструментарий Go

    Помимо компилятора и тестов, Go поставляется с набором утилит, которые стандартизируют процесс разработки.

    go fmt

    Вам больше не нужно спорить с коллегами о том, где ставить фигурные скобки или использовать ли табы вместо пробелов. Утилита go fmt автоматически форматирует ваш код в соответствии с единым стандартом Go.

    > «Gofmt's style is no one's favorite, yet gofmt is everyone's favorite.» > — Роб Пайк (Rob Pike), один из создателей Go. Источник

    go vet

    Это статический анализатор кода. Он ищет подозрительные конструкции, которые компилируются, но могут содержать логические ошибки (например, неправильное использование спецификаторов в Printf или потерянные вызовы мьютексов).

    Заключение

    Мы рассмотрели экосистему, которая делает Go таким эффективным инструментом:

    * Модули позволяют легко управлять зависимостями и гарантируют воспроизводимость сборок. * Встроенное тестирование и табличные тесты поощряют написание качественного и проверяемого кода. * Стандартная библиотека предоставляет мощные инструменты для работы с сетью, файлами и данными «из коробки». * Утилиты вроде go fmt снимают когнитивную нагрузку, позволяя сосредоточиться на логике, а не на оформлении.

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