Перейти к основному содержимому

Первая программа на Go

Разработчику Архитектору

Play ITЗагрузка интерактивного демо…


Первая программа на Go

Где применяют Go

Go компилируется в один бинарник, стартует быстро и хорошо подходит для CLI, микросервисов и DevOps-утилит. В отличие от интерпретируемого Python, ошибки типов ловятся до запуска. Модуль go.mod заменил старый $GOPATH — проект можно хранить где угодно.

После Hello, Go логично: Gin / Echo / Fiber для REST, Веб на stdlib без фреймворка.


Что получится

Каталог с go.mod, main.go, команды go run и go build — исполняемый файл без установленного Go на целевой машине (того же OS/архитектуры).


Go — это компилируемый язык, и для работы с ним требуется установка toolchain — набора утилит командной строки, включающего в себя компилятор go, менеджер зависимостей, средство сборки, тестирования и анализа кода. Этот инструментарий распространяется как единый пакет, доступный для всех основных операционных систем: Windows, macOS и Linux.

Для написания кода не требуется установка тяжёлой интегрированной среды разработки (IDE) вроде IntelliJ IDEA или Visual Studio. Хотя такие среды поддерживают Go через плагины (GoLand, VS Code с расширением Go и др.), на начальном этапе достаточно текстового редактора с базовой поддержкой синтаксиса и возможностью вызова команд из терминала. Наиболее популярным и рекомендуемым выбором является Visual Studio Code — лёгкий, кроссплатформенный редактор с открытым исходным кодом, разрабатываемый Microsoft. Его преимущества включают:
— встроенную интеграцию с терминалом,
— поддержку автодополнения, навигации по коду и рефакторинга через официальное расширение Go от команды Go,
— прозрачную работу с модулями, тестами и профилированием,
— отсутствие необходимости в настройке сложной инфраструктуры для старта.

Альтернативные варианты включают:
Vim или Neovim с плагинами vim-go и coc.nvim, если предпочтителен клавиатурно-ориентированный подход и минимализм,
Sublime Text с пакетом GoSublime,
GoLand от JetBrains — полноценная IDE для Go; полный обзор (установка, интерфейс, отладка горутин) — в статье GoLand — IDE для разработки на Go. Оптимальна при интенсивной разработке; для первых шагов достаточно VS Code.

Выбор редактора не влияет на сам процесс компиляции и запуска, так как сборка проекта производится исключительно через команды go build и go run, независимо от среды написания. Поэтому дальнейшее описание будет ориентировано на универсальный сценарий: использование Visual Studio Code в сочетании с системным терминалом (или встроенным терминалом редактора). Если вы выбрали GoLand — те же шаги с go mod и main.go выполняются в IDE; см. раздел "Первая программа в GoLand" в GoLand — IDE для разработки на Go.


Установка Go

Установка программ обычно выглядит так (официальный .msi на Windows):

Play ITЗагрузка интерактивного демо…

Первым действием является загрузка официального дистрибутива с сайта golang.org/dl. На странице представлены установочные пакеты для всех поддерживаемых платформ — .msi для Windows, .pkg для macOS, .tar.gz для Linux. Рекомендуется выбирать последнюю стабильную версию, обозначаемую как Stable. На момент написания главы это Go 1.23.x, но версия может измениться — ориентироваться следует на дату релиза и пометку Stable, а не на номер.

Для Linux и macOS рекомендуется использовать архивный вариант (goX.XX.X.linux-amd64.tar.gz или аналогичный). Установка производится вручную — архив распаковывается в системную директорию, например /usr/local, после чего исполняемые файлы становятся доступны глобально. Типичная последовательность команд в терминале:

# Скачивание архива (пример для amd64-системы)
wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz

# Удаление предыдущей установки Go, если она есть в /usr/local/go
sudo rm -rf /usr/local/go

# Распаковка архива в /usr/local
sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz

# Добавление /usr/local/go/bin в PATH (в ~/.bashrc или ~/.zshrc)
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

Разбор:

  • wget ...tar.gz скачивает архив дистрибутива Go для нужной платформы.
  • sudo rm -rf /usr/local/go удаляет старую версию, чтобы не получить конфликт бинарников.
  • sudo tar -C /usr/local -xzf ... распаковывает новый toolchain в стандартный путь.
  • export PATH=... добавляет go в переменные окружения, чтобы команда была доступна из любого каталога.
  • source ~/.bashrc применяет изменения в текущей сессии без перезапуска терминала.

Проверка установки (новый сеанс терминала; ожидается строка вида go version go1.23.1 linux/amd64):

go version

Разбор:

  • Команда показывает текущую версию Go и целевую платформу.
  • Этот шаг подтверждает, что бинарник найден в PATH.
  • Если команда не выполняется, нужно проверить путь установки и переменные окружения.

Для Windows достаточно .msi-инсталлятора (добавляет go.exe в PATH); проверка — та же команда в cmd или PowerShell.

Go не требует JVM, .NET Runtime и т.п. — базовый инструментарий:

go mod init example.com/hello
go build
go run .
go test ./...
go fmt ./...
go vet ./...

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


Структура проекта и организация исходного кода

В отличие от некоторых языков, где проекты жёстко привязаны к определённой иерархии каталогов (например, Maven-структура в Java), Go с версии 1.11 перешёл на модель модулей (go modules), которая полностью освободила разработчика от необходимости размещать код внутри $GOPATH. Теперь каждый проект — это автономная директория с файлом go.mod, описывающим его идентификатор, версию и зависимости.

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


Шаг 1 — Создание рабочей директории

Выберите локацию на диске — например, ~/projects/hello-go (для Linux/macOS) или C:\Users\<имя>\projects\hello-go (для Windows). Создайте каталог любым удобным способом: через командную строку (mkdir -p ~/projects/hello-go), проводник или встроенные средства редактора.


Шаг 2 — Инициализация модуля

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

cd ~/projects/hello-go
go mod init hello-go

Команда создаёт файл go.mod следующего содержания:

module hello-go

go 1.23

Здесь hello-go — это модульный путь (module path), уникальный идентификатор проекта. На данном этапе он может быть произвольным, но по соглашению он часто совпадает с относительным путём или формируется как доменное имя в обратном порядке (например, example.com/hello). Для локальных экспериментов допустимо использовать простое имя без точки, хотя в продакшене рекомендуется применять доменные имена для избежания коллизий.

Файл go.mod — центральный элемент управления зависимостями. При добавлении внешних библиотек (например, через go get github.com/some/library) в него автоматически добавляются записи require, фиксирующие точные версии. Для первой программы зависимости отсутствуют, и файл остаётся минимальным.

go get github.com/some/library

Шаг 3 — Создание исходного файла

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

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


Написание кода

Go следует строгой дисциплине оформления кода. Каждая программа начинается с объявления пакета. Пакет — это логическая единица кодовой базы, объединяющая один или несколько файлов. Пакет main имеет особый статус: он обозначает исполняемое приложение. Библиотеки, напротив, используют именованные пакеты, такие как http, fmt, os, и не содержат функции main.

После объявления пакета следует секция импорта — перечисление сторонних пакетов, функциональность которых требуется в текущем файле. Для вывода текста в консоль используется стандартный пакет fmt (от format), предоставляющий функции форматированного ввода-вывода, включая Println, Printf, Scanf и другие.

Тело программы состоит из функций. Единственная обязательная функция в исполняемом приложении — main. Она не принимает аргументов и не возвращает значений. Это точка входа — с неё начинается выполнение программы после загрузки и инициализации всех пакетов.

Типичный минимальный код выглядит так:

package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

Разбор:

  • package main обозначает исполняемую программу, а не библиотечный пакет.
  • import "fmt" подключает стандартный пакет форматированного ввода-вывода.
  • func main() — точка входа, с которой runtime начинает выполнение.
  • fmt.Println(...) печатает строку в stdout и автоматически добавляет перевод строки.

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

package main — объявление принадлежности файла к главному исполняемому пакету. Эта строка обязательна и должна быть первой (после возможных комментариев).

import "fmt" — директива импорта. Она указывает, что в коде будут использоваться экспортируемые идентификаторы из пакета fmt. Имя пакета при импорте совпадает с именем директории внутри $GOROOT/src (для стандартной библиотеки) или репозитория (для внешних). Экспортируемые идентификаторы — это те, чьи имена начинаются с заглавной буквы — Println, Error, Reader и т.д. Внутренние (непубличные) идентификаторы, начинающиеся со строчной буквы (println, errorf), недоступны вне пакета.

func main() { ... } — определение функции. Ключевое слово func вводит сигнатуру функции. Скобки () обозначают отсутствие параметров. Фигурные скобки {} ограничивают тело функции — блок кода, выполняемый при вызове.

fmt.Println("Hello, World!") — вызов функции Println из пакета fmt. Эта функция принимает произвольное число аргументов любого типа, преобразует их в строковое представление, объединяет пробелами и выводит в стандартный поток вывода stdout, завершая строку символом перевода строки \n. Аргумент "Hello, World!" — строковый литерал в двойных кавычках. В Go строки неизменяемы и кодируются в UTF-8 по умолчанию.

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

Также важна идентация: тело функции сдвинуто на одну табуляцию (или 4 пробела — настройка редактора). Go не требует строгого соответствия стилю, но инструмент go fmt автоматически приводит код к каноническому виду, включая выравнивание, пробелы вокруг операторов и порядок импортов. Регулярное применение go fmt рекомендуется даже на начальном этапе — это формирует дисциплину и совместимость с экосистемой.


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

После сохранения файла main.go программа готова к запуску. Go предоставляет два основных способа: интерпретируемый (на самом деле — компиляция в памяти с немедленным запуском) и компиляция в отдельный исполняемый файл.


Способ 1 — go run

Самый быстрый путь — go run с именем файла (или маской *.go):

go run main.go

Разбор:

  • go run компилирует исходник во временный бинарник и сразу запускает его.
  • Команда удобна для быстрых проверок при разработке.
  • Для больших проектов может быть медленнее отдельного запуска собранного файла, потому что включает фазу компиляции каждый раз.

Результат выполнения:

Hello, World!

Под капотом go run выполняет следующие действия:
— анализирует зависимости модуля через go.mod,
— при необходимости загружает недостающие пакеты (в данном случае — только стандартная библиотека, уже присутствующая в дистрибутиве),
— компилирует исходный код в машинный код целевой архитектуры,
— создаёт временный исполняемый файл в системном каталоге (например, /tmp/go-build...),
— запускает его, передавая аргументы командной строки (если указаны),
— после завершения удаляет временный файл.

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


Способ 2 — go build и запуск исполняемого файла

Для получения постоянного артефакта используется go build:

go build -o hello

Флаг -o задаёт имя выходного файла. Без него имя совпадает с именем директории (hello-go на Unix-системах или hello-go.exe на Windows). Результат — нативный бинарный файл, не требующий интерпретатора или дополнительных библиотек. Его можно запустить напрямую:

./hello # Linux/macOS
hello.exe # Windows (в PowerShell или cmd)

Преимущества этого подхода:
— отсутствие накладных расходов на компиляцию при каждом запуске,
— возможность передачи файла другому пользователю (на той же ОС и архитектуре) без установки Go,
— интеграция в CI/CD-конвейеры, где сборка и запуск разделены во времени.

Go поддерживает кросс-компиляцию без дополнительных инструментов: достаточно задать переменные окружения GOOS и GOARCH перед сборкой. Например, сборка Windows-версии на Linux:

GOOS=windows GOARCH=amd64 go build -o hello.exe

Полученный hello.exe будет работать на любой 64-битной Windows-машине без установки зависимостей.


Анализ окружения Go

После установки просмотрите переменные окружения Go (см. блок ниже). Знание параметров необходимо для диагностики и понимания поведения инструментария.

Просмотр переменных окружения Go:

go env
go env GOROOT

Ключевые переменные:

  • GOROOT — путь к корневой директории установленного дистрибутива Go (например, /usr/local/go). Внутри находятся подкаталоги bin (исполняемые утилиты), src (исходный код стандартной библиотеки), pkg (скомпилированные пакеты). Эта переменная устанавливается автоматически при корректной инсталляции и редко требует ручной настройки.

  • GOPATH — исторически это был обязательный путь к рабочему пространству, содержащему src, bin, pkg. С введением модулей (Go 1.11+) GOPATH стал опциональным: проекты могут размещаться в любом месте файловой системы. Однако каталог GOPATH/bin по-прежнему используется как место установки глобальных утилит (например, golangci-lint, mockgen), если они устанавливаются через go install. По умолчанию GOPATH равен ~/go в домашней директории пользователя.

  • GOOS и GOARCH — целевая операционная система и архитектура процессора. По умолчанию совпадают с хост-системой, но могут быть переопределены для кросс-компиляции. Поддерживаемые значения документированы в официальной спецификации — GOOS включает linux, darwin (macOS), windows, freebsd и другие; GOARCHamd64, arm64, 386, ppc64le, s390x.

  • GO111MODULE — устаревшая переменная, управлявшая режимом модулей. В Go 1.16+ модули включены по умолчанию во всех контекстах, и эта настройка игнорируется. Упоминание необходимо только при работе с устаревшими версиями.

  • GOMOD — путь к файлу go.mod текущего модуля. Если команда запущена вне модуля, значение — /dev/null (Unix) или nul (Windows).

Выполнение go env без аргументов выводит все переменные; go env GOROOT — только указанную. Это стандартный способ верификации окружения перед началом работы, особенно при одновременном использовании нескольких версий Go (например, через gvm или asdf).

go env GOROOT

Принципы именования и организация кода в многофайловом проекте

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

  • Пакеты именуются строчными буквами, без подчёркиваний, цифр или дефисов. Короткие, ёмкие имена предпочтительны — http, json, bytes, errors. Имя пакета не обязано совпадать с именем каталога, но рекомендуется для избежания путаницы. Пакет импортируется по пути, указанному в import, но в коде обращение идёт по имени пакета, объявленному в первом файле каталога через package <имя>. Таким образом, import "net/http" даёт доступ к функциям через http.Get, а не net_http.Get.

  • Функции и типы в стандартной библиотеке и публичных API следуют принципу — экспортируемые идентификаторы — с заглавной буквы (Reader, Write, NewRequest), внутренние — со строчной (read, buf, err). Экспорт определяется не модификаторами доступа (их в Go нет), а регистром первой буквы. Это упрощает анализ видимости: достаточно взглянуть на имя.

  • Структура проекта для небольшой программы может быть плоской: один файл main.go, один go.mod. По мере роста сложности код разбивается на логические единицы:

    • cmd/ — каталог для точек входа. Если проект включает несколько исполняемых файлов (например, server и cli), каждый получает отдельную поддиректорию: cmd/server/main.go, cmd/cli/main.go.
    • internal/ — приватные пакеты, доступные только в рамках текущего модуля. Импорт извне запрещён механизмом сборки.
    • pkg/ — публичные утилиты, предназначенные для переиспользования (менее распространено в современных проектах, где предпочитают выносить такие компоненты в отдельные модули).
    • go.mod и go.sum находятся в корне.

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


Расширение программы

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

Go — язык со статической типизацией и выводом типов. Переменная может быть объявлена явно:

var name string = "World"

или сокращённо, с автоматическим выводом типа по правой части:

name := "World"

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

Тип string в Go — это неизменяемая последовательность байтов в кодировке UTF-8. Длина строки определяется функцией len(), количество Unicode-символов (рун) — utf8.RuneCountInString().

Добавим ввод имени пользователя:

Код ITЗагрузка примера кода…

Разбор:

  • bufio.NewReader(os.Stdin) создаёт буферизованный источник чтения из консоли.
  • ReadString('\n') читает строку до Enter и возвращает данные вместе с ошибкой.
  • Проверка if err != nil реализует идиоматичную обработку ошибок в Go.
  • name = name[:len(name)-1] удаляет завершающий символ перевода строки.
  • Конкатенация greeting := "Hello, " + name + "!" формирует пользовательский ответ.

Разберём нововведения.

import с группировкой в скобках — стандартный способ подключения нескольких пакетов. Порядок не важен, но go fmt сортирует их лексикографически.

bufio.NewReader(os.Stdin) — создание буферизованного читателя поверх стандартного потока ввода. Буферизация повышает эффективность при многократных операциях чтения.

reader.ReadString('\n') возвращает два значения: прочитанную строку и ошибку. Это идиоматичный для Go подход — множественные возвращаемые значения, где последний элемент почти всегда имеет тип error. Такая сигнатура заставляет разработчика явно обрабатывать исключительные ситуации, не полагаясь на исключения (в Go их нет).

if err != nil — проверка на наличие ошибки. Тип error — это встроенный интерфейс с одним методом Error() string. Любая ненулевая ошибка означает сбой в операции — например, конец файла при интерактивном вводе (редко), или прерывание потока.

os.Exit(1) завершает программу с кодом возврата 1, сигнализируя об ошибке. Код 0 — успешное завершение (по умолчанию при выходе из main).

name[:len(name)-1] — срез строки без последнего символа (\n). Это простейший способ очистки, хотя в реальных сценариях предпочтительнее strings.TrimSpace(name), удаляющий все управляющие символы по краям.

Обратите внимание — отсутствие try/catch, finally, throw. Обработка ошибок — линейная, декларативная, без скрытых ветвлений выполнения. Это делает поток управления предсказуемым и упрощает статический анализ.


Тестирование и верификация

Go включает фреймворк для написания и запуска тестов прямо в стандартной поставке. Тесты размещаются в файлах с суффиксом _test.go и содержат функции, начинающиеся с Test, принимающие единственный параметр типа *testing.T.

Создадим файл main_test.go в той же директории:

Код ITЗагрузка примера кода…

Изменим main.go, вынеся логику в buildGreeting:

Код ITЗагрузка примера кода…

В корне проекта запустите тесты:

go test
PASS
ok hello-go 0.001s

При неудаче вывод включает диагностику, номер строки и описание ошибки. Подробный режим:

go test -v

Тесты не требуют внешних зависимостей, запускаются параллельно, поддерживают бенчмарки (BenchmarkXxx), примеры (ExampleXxx) и coverage-анализ (go test -cover). Это делает их неотъемлемой частью процесса разработки.

go test -cover

Инструменты сопровождения

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

  • go fmt — форматирование исходного кода по каноническим правилам — отступы табуляцией, пробелы вокруг операторов, выравнивание импортов, перенос длинных строк. Работает рекурсивно по всем .go-файлам в текущем каталоге и подкаталогах. Не требует настройки — правила фиксированы и едины для всей экосистемы.

  • go vet — статический анализ на наличие подозрительных конструкций — неиспользуемых переменных, небезопасных преобразований, ошибок форматирования в fmt.Printf, несинхронизированного доступа к разделяемым данным и других типичных антипаттернов. Выполняется как часть go test, но может запускаться отдельно.

  • go doc — генерация и просмотр документации прямо в терминале. Например, go doc fmt.Println выводит сигнатуру и описание функции. Документация извлекается из комментариев, непосредственно предшествующих объявлению и начинающихся с имени сущности:

go doc fmt.Println
// buildGreeting constructs a greeting message for the given name.
// It appends name to the prefix "Hello, " and adds trailing exclamation mark.
func buildGreeting(name string) string { ... }

Такой комментарий будет включён в go doc . buildGreeting.

go doc . buildGreeting
  • gofmt -d — показывает, какие изменения внесёт go fmt, без модификации файлов. Полезно для проверки перед коммитом.

Эти инструменты интегрированы в редакторы (например, VS Code автоматически запускает go fmt при сохранении), что делает соблюдение стандартов невидимым и необременительным.


Зависимости и управление версиями

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

Когда в коде появляется import "github.com/someuser/somepackage", Go при первом запуске go run или go build:

  1. Ищет пакет в кеше модулей ($GOPATH/pkg/mod или $GOCACHE).
  2. Если отсутствует — загружает репозиторий через git, hg или svn.
  3. Выбирает версию, если указан тег (например, v1.2.3), или последний коммит в ветке по умолчанию.
  4. Записывает точную версию в go.mod и контрольную сумму в go.sum.
  5. Компилирует пакет и кэширует объектный файл.

Добавим лёгкую зависимость — пакет для цветного вывода github.com/fatih/color:

go get github.com/fatih/color@v1.17.0

Файл go.mod обновится:

module hello-go

go 1.23

require github.com/fatih/color v1.17.0

Файл go.sum получит хеши содержимого — это гарантия неизменности зависимостей между сборками.

Изменённый main.go:

Код ITЗагрузка примера кода…

Теперь приветствие выводится зелёным цветом в терминале, поддерживающем ANSI-коды. Важно: зависимость добавлена только в go.mod, не в vendor/. Go по умолчанию использует глобальный кеш; локальную копию зависимостей при необходимости создают так:

go mod vendor

Дополнительные сниппеты с разбором

Чтение аргументов командной строки

package main

import (

"flag"
"fmt"
)

func main() {
name := flag.String("name", "World", "имя для приветствия")
flag.Parse()
fmt.Printf("Hello, %s!\n", *name)
}

Разбор:

  • flag.String(...) объявляет флаг -name с значением по умолчанию.
  • flag.Parse() разбирает аргументы, переданные при запуске программы.
  • *name разыменовывает указатель и даёт фактическое строковое значение.
  • Сниппет показывает, как превратить статический пример в удобный CLI.

Простая табличная проверка функции

Код ITЗагрузка примера кода…

Разбор:

  • Таблица cases позволяет проверить несколько сценариев единообразно.
  • Цикл по кейсам уменьшает дублирование кода тестов.
  • t.Fatalf сразу прерывает тест при несоответствии результата.
  • Это базовый формат, из которого строится большая часть тестов в Go-проектах.

Частые ошибки

СимптомПричина
go: command not foundGo не в PATH — проверьте go version в новом терминале
cannot find moduleНе в каталоге модуля или нет go mod init
package main is not in GOROOTФайл не в package main или нет func main()
Зависимость не подтягиваетсяЗабыли go mod tidy после правки go.mod

Что попробовать

  1. go test ./... — добавьте _test.go к функции buildGreeting.
go test ./...
  1. CLI-флаги: пакет flag для имени в приветствии.
  2. REST-сервер: Gin после этого гайда.

Дальше


Частые ошибки

СимптомПричина
go: command not foundGo не в PATH — проверьте go version в новом терминале
cannot find moduleНе в каталоге модуля или нет go mod init
package main is not in GOROOTФайл не в package main или нет func main()
Зависимость не подтягиваетсяЗабыли go mod tidy после правки go.mod

Что попробовать

  1. go test ./... — добавьте _test.go к функции buildGreeting.
go test ./...
  1. CLI-флаги: пакет flag для имени в приветствии.
  2. REST-сервер: Gin после этого гайда.

Дальше


В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

Первые шаги (маршрут подборки) — Первая программа на PHP, Первая программа на C#, Первая программа на Java, Первая программа на C++, Первая программа на Python, Первая программа на TypeScript.