Go на практике: от синтаксиса до веб-сервисов

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

1. Основы языка и инструменты: пишем первый консольный калькулятор

Основы языка и инструменты: пишем первый консольный калькулятор

Добро пожаловать в курс Go на практике. Мы не будем тратить время на скучную теорию без дела. Философия этого курса проста: мы изучаем концепцию и сразу же применяем её в реальном коде. К концу курса вы пройдете путь от «Hello World» до написания собственных микросервисов.

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

Почему Go?

Язык Go (или Golang) был разработан в Google для решения конкретных проблем: долгая сборка проектов, сложная работа с зависимостями и трудности в написании конкурентного кода.

Go — это компилируемый, статически типизированный язык. Это значит, что:

  • Компилируемый: код превращается в бинарный файл (машинный код), который можно запустить на сервере даже без установленного Go.
  • Статически типизированный: если вы сказали, что переменная — это число, она не может внезапно стать строкой. Это спасает от тысяч глупых ошибок.
  • Установка инструментов

    Прежде чем писать код, нам нужно подготовить рабочее место.

    1. Компилятор Go

    Зайдите на официальный сайт Go и скачайте установщик для вашей операционной системы (Windows, macOS или Linux). Установка проходит в режиме «Далее — Далее — Готово».

    Чтобы проверить, что всё прошло успешно, откройте терминал (или командную строку) и введите:

    Вы должны увидеть что-то вроде go version go1.21.0 ....

    2. Среда разработки (IDE)

    Писать код в блокноте можно, но больно. Я рекомендую два варианта: VS Code: Бесплатный, легкий. Обязательно установите расширение Go* от команды Go Team. * GoLand: Платный (есть пробный период), мощный, от JetBrains. Идеален для больших проектов.

    Анатомия Go-программы

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

    Разберем каждую строку:

  • package main: Эта строка говорит компилятору, что этот файл — исполняемая программа, а не библиотека. Точка входа в любую программу на Go всегда находится в пакете main.
  • import "fmt": Мы подключаем пакет fmt (format). В Go очень богатая стандартная библиотека. Пакет fmt отвечает за ввод и вывод данных (печать текста на экран).
  • func main() { ... }: Это главная функция. Когда вы запускаете программу, выполнение кода начинается именно отсюда.
  • !Структура базового файла на языке Go

    Переменные и типы данных

    Для нашего калькулятора нам нужно где-то хранить числа и операцию, которую выбрал пользователь. Для этого нужны переменные.

    В Go есть два основных способа создать переменную:

    1. Полная декларация

    Используется ключевое слово var. Мы явно указываем имя и тип.

    2. Краткая декларация (Магия Go)

    Внутри функций можно использовать оператор :=. Go сам догадается, какой тип у переменной, посмотрев на значение справа.

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

    Для калькулятора нам понадобятся: * float64 — для чисел с плавающей точкой (ведь мы можем захотеть разделить 5 на 2). string — для знака операции (+, -, , /).

    Логика выбора: if и switch

    Калькулятор должен уметь принимать решения. «Если пользователь ввел плюс, нужно сложить».

    Конструкция if-else

    Классическая проверка условия. Обратите внимание: круглые скобки вокруг условия в Go не нужны.

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

    Когда вариантов много (как операций в калькуляторе), switch подходит лучше. Он выглядит чище.

    В отличие от других языков (C++, Java), в Go не нужно писать break после каждого case. Go выполняет только один подходящий блок и выходит из switch.

    Практика: Пишем консольный калькулятор

    Теперь соберем всё вместе. Наша цель — программа, которая:

  • Спрашивает первое число.
  • Спрашивает второе число.
  • Спрашивает операцию.
  • Выводит результат.
  • Создайте папку для проекта, откройте её в терминале и инициализируйте модуль (это создаст файл go.mod для управления зависимостями, хорошая привычка с самого начала):

    Теперь создайте файл main.go и начнем писать код.

    Шаг 1: Импорты и переменные

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

    Шаг 2: Чтение данных

    Для ввода данных используем fmt.Scan. Эта функция считывает данные из консоли и кладет их в переменную.

    Почему &a? Символ & означает, что мы передаем не значение переменной (которое пока пустое), а адрес в памяти, где эта переменная лежит. Функция Scan пойдет по этому адресу и запишет туда то, что вы введете с клавиатуры.

    Шаг 3: Логика вычислений

    Теперь самое интересное. Используем switch для обработки операций.

    Здесь мы добавили важную проверку. В математике деление на ноль не определено. Если мы попытаемся разделить на ноль, программа должна нас остановить.

    Математически мы проверяем условие:

    где — это делитель (второе введенное число). Если равно нулю, операция невозможна.

    Также мы использовали fmt.Printf. Это «форматированный вывод». Символ %f заменяется на значение переменной res. \n означает перенос строки.

    Полный код проекта

    Вот что у вас должно получиться в файле main.go:

    Небольшое улучшение: я заменил %f на %.2f в последней строке. Это скажет Go выводить только два знака после запятой, чтобы результат выглядел аккуратнее (например, 5.00 вместо 5.000000).

    Запуск программы

    У нас есть два пути запуска:

  • Быстрый запуск (для разработки):
  • Команда компилирует и сразу запускает программу, не создавая exe-файл.

  • Компиляция (для релиза):
  • Команда создает бинарный файл (например, calculator.exe на Windows). После этого вы можете запустить созданный файл как обычную программу.

    Попробуйте запустить свой калькулятор и посчитать что-нибудь!

    Резюме

    Сегодня вы сделали огромный шаг. Вы не просто узнали синтаксис, вы: * Настроили профессиональное окружение. * Поняли структуру Go-файлов (package, import, func). * Научились работать с переменными и вводом/выводом. * Написали работающую программу с логикой ветвления.

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

    2. Сложные типы данных и структуры: создание менеджера задач (To-Do List)

    Сложные типы данных и структуры: создание менеджера задач (To-Do List)

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

    Сегодня мы перейдем на следующий уровень. Мы разберем, как Go работает с коллекциями данных, создадим свои собственные типы данных и напишем консольный менеджер задач (To-Do List), который будет хранить ваши дела.

    Массивы и Слайсы: в чем разница?

    Во многих языках есть понятие «массив» или «список». В Go есть два понятия: Array (Массив) и Slice (Слайс/Срез). Понимание разницы между ними — ключ к эффективной работе.

    Массивы (Arrays)

    Массив в Go — это структура фиксированной длины. Если вы создали массив на 5 элементов, он не может стать больше или меньше.

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

    Где — итоговый адрес ячейки памяти, — базовый адрес начала массива, — индекс элемента (номер ячейки), а — размер одного элемента в байтах (например, 8 байт для int64).

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

    Слайсы (Slices)

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

    !Структура слайса: он не хранит данные сам, а указывает на массив, где они лежат

    Создание слайса:

    Главная магия слайсов — функция append. Она добавляет элемент в конец списка, автоматически увеличивая его размер.

    > Важно: Функция append возвращает новый (или обновленный) слайс, поэтому мы обязательно должны присвоить результат обратно переменной: tasks = append(tasks, ...).

    Карты (Maps): хранение пар «Ключ-Значение»

    Иногда нам нужно найти значение не по индексу (0, 1, 2), а по имени или ID. Для этого существуют Maps (в других языках: словари, хеш-таблицы, ассоциативные массивы).

    Если вы запросите ключ, которого нет, Go не выдаст ошибку, а вернет «нулевое значение» для типа данных (0 для чисел, пустая строка для строк).

    Структуры (Structs): создаем свои типы

    Слайсы и карты хороши, но что, если нам нужно описать сложный объект? Например, задачу в нашем списке. У задачи есть:

  • Название (string)
  • Описание (string)
  • Статус выполнения (bool)
  • Хранить это в разных массивах неудобно. На помощь приходят структуры.

    Теперь Task — это полноценный тип данных, как int или string. Мы можем создавать переменные этого типа:

    Циклы: Range

    В Go есть только один вид цикла — for. Но он умеет всё. Чтобы пройтись по слайсу или карте, используется ключевое слово range.

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

    Практика: Пишем To-Do List

    Теперь применим знания. Мы напишем программу, которая:

  • Хранит список задач (используя struct и slice).
  • Позволяет добавлять задачи.
  • Позволяет просматривать список.
  • Позволяет отмечать задачи как выполненные.
  • Создайте новую папку и файл main.go.

    Шаг 1: Подготовка и структура

    Нам понадобится пакет bufio для чтения строк с пробелами (так как fmt.Scan читает только до первого пробела).

    Шаг 2: Главный цикл приложения

    Мы будем крутить программу в бесконечном цикле for, пока пользователь не введет команду выхода.

    Шаг 3: Реализация команд

    Добавим код внутрь case блоков.

    Добавление (add):

    Просмотр (list): Здесь мы используем цикл range. Также добавим красивое отображение галочки выполнения.

    Завершение задачи (done): Пользователь введет номер задачи, а мы пометим её как выполненную. Нам нужно будет обратиться к элементу слайса по индексу.

    Полный код

    Соберите все части вместе в main.go. Запустите программу через go run main.go.

    Попробуйте:

  • Ввести add, затем Купить молоко.
  • Ввести add, затем Изучить Go.
  • Ввести list.
  • Ввести done, затем 1.
  • Снова list, чтобы увидеть результат.
  • Резюме

    Сегодня вы освоили инструменты, которыми Go-разработчики пользуются каждый день: * Слайсы — для динамических списков. * Структуры — для создания собственных объектов. * Циклы Range — для удобного перебора данных.

    Ваш To-Do List работает, но пока он "забывает" все задачи после перезапуска программы, так как хранит их в оперативной памяти. В будущих уроках мы научимся сохранять данные в файлы и базы данных.

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

    3. Интерфейсы и композиция: проектирование гибкой системы уведомлений

    Интерфейсы и композиция: проектирование гибкой системы уведомлений

    Привет, Gopher! В прошлых статьях мы научились работать с базовыми типами, управлять потоком выполнения и создавать собственные структуры данных, такие как задачи для нашего To-Do листа. Но что, если наше приложение растет?

    Представьте, что вы пишете сервис, который должен отправлять уведомления пользователям. Сегодня заказчик просит отправлять Email. Завтра он захочет SMS. Послезавтра — сообщения в Telegram. Если писать всё в одну кучу, ваш код превратится в запутанный клубок из условий if-else.

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

    Методы: оживляем структуры

    До сих пор наши структуры были просто контейнерами для данных. Но в Go мы можем научить их что-то делать. Функция, привязанная к конкретному типу, называется методом.

    Вспомним нашу структуру User:

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

    Теперь мы можем вызывать этот метод через точку, как в объектно-ориентированных языках:

    Интерфейсы: контракты поведения

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

    Это ключевая концепция полиморфизма в Go. Давайте создадим интерфейс для отправителя уведомлений.

    Любой тип, у которого есть метод Send, принимающий строку и возвращающий ошибку, автоматически удовлетворяет этому интерфейсу.

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

    Магия неявной реализации

    В Java или C# вам нужно писать implements Sender. В Go этого нет. Если метод совпадает по сигнатуре — интерфейс реализован. Это называется Duck Typing («Утиная типизация»): если это ходит как утка и крякает как утка, то это утка.

    Давайте создадим два разных сервиса:

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

    Композиция вместо наследования

    Многие новички ищут в Go возможность создать класс-родитель и унаследовать от него дочерние классы. В Go нет наследования. Вместо этого используется композиция (встраивание).

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

    Теперь Admin автоматически имеет доступ к полям и методам BaseUser. Это выглядит как наследование, но технически Admin содержит в себе BaseUser.

    Практика: Система уведомлений

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

    Создайте файл main.go:

    Разбор кода

  • Полиморфизм: Слайс []Notifier хранит разнородные объекты. Для компилятора они все равны, потому что умеют делать Notify.
  • Расширяемость: Если завтра нам нужно добавить Push-уведомления, мы просто создадим структуру Push с методом Notify. Нам не придется переписывать основной цикл рассылки.
  • Композиция: Структура SuperUser собрана из готовых кирпичиков (Email и Telegram).
  • Пустой интерфейс: interface{}

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

    > Совет: Используйте пустой интерфейс с осторожностью. Когда вы используете interface{}, вы отключаете строгую типизацию — главную защиту Go от ошибок. Компилятор перестает понимать, что именно лежит в переменной.

    Резюме

    Сегодня вы перешли от процедурного стиля к архитектурному проектированию:

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

    В следующей статье мы разберем Goroutines и Channels — то, что делает Go королем параллельного программирования. Мы научимся выполнять тысячи задач одновременно!

    4. Магия конкурентности: горутины и каналы в разработке быстрого чекера сайтов

    Магия конкурентности: горутины и каналы в разработке быстрого чекера сайтов

    Приветствую, Gopher! Мы уже прошли долгий путь: от «Hello World» до сложных структур и интерфейсов. Наши программы работают правильно и надежно. Но есть один нюанс: пока что они делают всё последовательно.

    Представьте, что вы готовите завтрак. Вы сначала жарите яйца (5 минут), потом режете хлеб (1 минута), потом варите кофе (3 минуты). Итого: 9 минут. Но ведь можно включить кофеварку, кинуть хлеб в тостер и жарить яйца одновременно! В программировании это называется конкурентность.

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

    Горутины (Goroutines): Легковесные потоки

    В других языках (Java, C++, Python) создание нового потока (thread) — это дорогая операция, потребляющая много памяти (часто 1-2 МБ на поток). В Go придумали горутины.

    Горутина — это функция, которая выполняется конкурентно с другими функциями. Она занимает всего около 2 КБ памяти при старте. Вы можете запустить миллионы горутин на обычном ноутбуке, и он не зависнет.

    !Горутины — это легкие и быстрые исполнители задач

    Как запустить горутину?

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

    Если убрать time.Sleep, программа, скорее всего, ничего не выведет из sayHello. Почему? Потому что функция main — это тоже горутина. Когда main завершается, программа закрывается, убивая все остальные горутины, даже если они не закончили работу.

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

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

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

  • Мы говорим: «Жди 5 задач» (Add).
  • Каждая задача по завершении говорит: «Я всё» (Done).
  • Главная функция ждет, пока счетчик не станет равен нулю (Wait).
  • Каналы (Channels): Общение между горутинами

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

    Философия Go гласит: > Не общайтесь, используя общую память. Вместо этого делитесь памятью через общение.

    Для этого существуют каналы. Представьте их как трубы, по которым горутины передают данные.

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

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

    Практика: Быстрый чекер сайтов

    Давайте напишем реальный инструмент. У нас есть список сайтов, и мы хотим проверить, работают ли они (отвечают ли статусом 200).

    Версия 1: Последовательная (Медленная)

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

    Математически время выполнения выражается так:

    где — общее время последовательного выполнения, — количество сайтов, а — время проверки -го сайта.

    Если у нас 10 сайтов и каждый отвечает за 1 секунду, мы будем ждать 10 секунд.

    Версия 2: Конкурентная (Быстрая)

    Мы запустим проверку каждого сайта в отдельной горутине. Результаты будем собирать через канал.

    Создайте файл main.go:

    Разбор кода

  • checkUrl: Функция делает HTTP-запрос. Вместо return она отправляет результат в канал c <- ....
  • go checkUrl(...): Мы запускаем проверку в фоне. Цикл for пролетает мгновенно, запуская 5 горутин.
  • Сбор данных: Второй цикл for ждет ровно 5 сообщений из канала. Как только сообщение приходит, оно печатается.
  • При идеальном распараллеливании время выполнения стремится к времени самого медленного запроса:

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

    В реальности есть небольшие накладные расходы, но ускорение будет колоссальным. Вместо 5-10 секунд программа отработает за 1-2 секунды.

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

    В примере выше мы использовали обычный (небуферизированный) канал. Это значит, что отправка c <- val блокирует горутину, пока кто-то не прочитает <-c.

    Иногда полезно иметь «запас» места в канале. Это называется буферизированный канал.

    Резюме

    Сегодня вы открыли для себя суперсилу Go: * Горутины позволяют делать много дел одновременно с минимальными затратами ресурсов. * WaitGroup помогает дождаться завершения всех задач. * Каналы позволяют безопасно передавать данные между горутинами без использования глобальных переменных и мьютексов.

    Теперь ваш чекер сайтов работает молниеносно. Но что, если нам нужно сделать из этого настоящий веб-сервис, который принимает запросы от пользователей через браузер? В следующей статье мы изучим стандартную библиотеку net/http и напишем свой первый веб-сервер!

    5. Сетевое программирование: разработка полноценного REST API сервиса для библиотеки книг

    Сетевое программирование: разработка полноценного REST API сервиса для библиотеки книг

    Привет, Gopher! В прошлых статьях мы прошли огромный путь: от простых переменных до конкурентного запуска тысяч горутин. Мы научились писать консольные утилиты, но современный мир требует большего. Сегодня программы редко живут в вакууме — они общаются друг с другом через сеть.

    В этой статье мы превратим ваш компьютер в веб-сервер. Мы не будем использовать сторонние фреймворки (как Gin или Echo), потому что стандартная библиотека Go настолько мощная, что позволяет писать production-ready сервисы «из коробки». Наша цель — создать REST API для цифровой библиотеки.

    Что такое REST API?

    Прежде чем писать код, разберемся с терминами. API (Application Programming Interface) — это контракт, по которому одна программа может попросить другую что-то сделать.

    REST (Representational State Transfer) — это стиль архитектуры, где мы работаем с ресурсами (книгами, пользователями) через стандартные HTTP-методы:

    * GET — получить данные (дай мне список книг). * POST — создать данные (добавь новую книгу). * PUT/PATCH — обновить данные (измени название книги). * DELETE — удалить данные (удали книгу).

    !Схема обмена данными: Клиент отправляет запрос, Сервер возвращает JSON-ответ

    Инструменты стандартной библиотеки

    Нам понадобятся два основных пакета:

  • net/http — сердце веб-разработки в Go. Он умеет слушать порт, принимать соединения и отправлять ответы.
  • encoding/json — инструмент для перевода структур Go в формат JSON (текстовый формат обмена данными) и обратно.
  • Шаг 1: Проектируем структуру данных

    Любой сервис начинается с данных. Наша сущность — Книга. Создайте файл main.go и опишите структуру.

    Обратите внимание на странные записи вроде ` json:"title" . Это теги структур. Они говорят кодировщику JSON: «Когда будешь превращать эту структуру в текст, назови поле Title маленькими буквами title». Это стандарт в веб-разработке.

    Шаг 2: Пишем первый обработчик (Handler)

    Обработчик — это функция, которая принимает запрос от пользователя и пишет ответ. В Go сигнатура обработчика всегда одинаковая:

    * w (Writer) — сюда мы пишем ответ (текст, JSON, статус-код). * r (Request) — отсюда мы читаем данные запроса (какой URL, какой метод, какое тело).

    Давайте напишем функцию, которая возвращает список всех книг.

    Всё просто! json.NewEncoder(w) создает кодировщик, который пишет сразу в поток вывода w. Метод Encode(library) берет наши данные и превращает их в строку вида [{"id":1, "title":"..."}].

    Шаг 3: Обработка создания книги (POST)

    Теперь сложнее. Нам нужно прочитать JSON, который прислал пользователь, превратить его в структуру Book и сохранить.

    Здесь мы используем http.Error для быстрой отправки ошибок. Это удобная обертка, которая устанавливает статус-код и пишет текстовое сообщение.

    Шаг 4: Маршрутизация и запуск сервера

    Теперь нам нужно сказать серверу: «Если пришли на адрес /books, вызывай этот код». До версии Go 1.22 маршрутизация была сложной, но теперь она стала намного удобнее. Однако, для понимания основ, мы объединим логику в одну функцию-распределитель.

    Функция http.ListenAndServe запускает бесконечный цикл, который принимает соединения. Если произойдет ошибка (например, порт занят), она вернет её, и log.Fatal завершит программу с сообщением.

    Полный код сервиса

    Соберите все части в один файл main.go. У вас должен получиться рабочий веб-сервер.

    Как проверить работу?

    Поскольку у нас нет фронтенда (кнопок и форм), мы будем использовать инструменты разработчика. Вы можете использовать программу Postman или консольную утилиту curl.

  • Запустите сервер:
  • Получить список книг (в другом окне терминала):
  • Ответ:
    [{"id":1,"title":"The Go Programming Language","author":"Alan Donovan","year":2015}]

  • Добавить книгу:
  • Ответ:
    {"id":2,"title":"Concurrency in Go"...}

    Работа с JSON: Marshaling и Unmarshaling

    В коде мы использовали Encoder и Decoder. Это потоковые методы, они хороши для HTTP. Но иногда вам нужно просто превратить структуру в строку или наоборот. Для этого есть функции:

    * json.Marshal(v) — превращает структуру v в байтовый срез (JSON). * json.Unmarshal(data, &v) — парсит JSON data и кладет результат в переменную v.

    > Важно: Чтобы пакет json мог читать и писать поля вашей структуры, они обязательно должны начинаться с заглавной буквы (быть экспортируемыми). Если вы назовете поле title (с маленькой буквы), JSON-кодировщик его просто проигнорирует.

    Резюме

    Поздравляю! Вы только что написали свой первый микросервис. Он пока хранит данные в оперативной памяти (и теряет их при перезагрузке), но он уже умеет общаться с внешним миром на универсальном языке HTTP и JSON.

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

  • Как работает пакет net/http`.
  • Как использовать теги структур для управления JSON.
  • Как писать обработчики для GET и POST запросов.
  • Как тестировать API с помощью curl.
  • В следующей статье мы решим проблему потери данных. Мы подключим к нашему сервису настоящую базу данных и научимся писать SQL-запросы прямо из Go кода. Готовьтесь, будет много практики!