Go — это язык, на котором пишут серверы, утилиты командной строки и большие распределённые системы. В этой главе мы не будем городить ничего сложного: напишем самую первую программу, разберём, из каких обязательных частей она состоит, и научимся выводить текст и значения на экран. К концу главы вы поймёте, что происходит, когда вы запускаете программу командой go run, чем она отличается от go build, и как печатать не только «Hello, world», но и числа, строки и даже типы переменных.
Никакого предыдущего опыта с Go не нужно. Если вы вообще никогда не писали код — тоже ничего страшного, мы идём медленно.
Для начала достаточно браузера и умения работать с текстом. Предыдущего опыта программирования не требуется. В примерах ниже можно менять код и запускать его; сначала попробуйте предсказать вывод, затем сравните с результатом. В конце каждой главы есть самостоятельное упражнение и проверка. Указанное время относится к чтению: на практику и исправление ошибок понадобится дополнительное время.
Полный пример начинается с package main и содержит func main(). Фрагменты без этого каркаса показывают отдельные части программы. Объявления func, type и методов из примеров размещайте вне main, рядом с ней. Вызовы функций, циклы и присваивания размещайте внутри main или другой функции. Например, func max(a, b int) int { ... } стоит отдельно, а fmt.Println(max(2, 7)) — внутри main. Обычный текст в кавычках — строка, числа пишутся без кавычек. Компьютер выполняет записанные действия; он не исправляет по смыслу опечатки и не угадывает пропущенные шаги.
Прежде чем писать, полезно понять три вещи о языке. Они объясняют, почему код выглядит именно так и почему ведёт себя предсказуемо.
Go компилируемый. Это значит, что ваш текст программы (исходный код) сначала переводится в машинный код — готовый исполняемый файл, который процессор понимает напрямую. В отличие от языков вроде Python или JavaScript, где код читает и исполняет отдельная программа-интерпретатор «на лету», у Go есть отдельный шаг — компиляция. Платим мы за это секундами ожидания при сборке, а получаем быстрый запуск и единый файл, который можно просто скопировать на сервер и запустить.
Go статически типизированный. У каждого значения есть тип, известный заранее: число, строка, логическое значение и так далее. Компилятор проверяет типы ещё до запуска. Если вы попробуете сложить строку с числом по ошибке, программа просто не соберётся — и вы узнаете о проблеме сразу, а не когда она уже «выстрелит» у пользователя. Это очень удобно: компилятор работает вашим первым ревьюером.
В Go есть сборщик мусора (garbage collector). Память под данные выделяется автоматически, и когда данные больше не нужны, среда исполнения сама их освобождает. Вам не нужно вручную «возвращать» память, как в C. Это снимает целый класс ошибок и даёт сосредоточиться на логике.
Держите эти три свойства в голове — они будут объяснять поведение Go во всех следующих главах.
Разберём по строчкам, потому что здесь нет ни одной лишней.
package main — это объявление пакета. Пакет — это набор файлов, которые живут вместе и образуют одну логическую единицу. Имя main особенное: оно говорит компилятору, что из этого пакета нужно собрать запускаемую программу, а не библиотеку. Если пакет называется иначе — это библиотека, которую подключают к другим программам.
import "fmt" подключает стандартный пакет fmt (от слова format). Именно в нём лежат функции для вывода текста, которыми мы пользуемся ниже. Чтобы пользоваться чужим кодом, его нужно сначала импортировать.
func main() — это функция с именем main. Она тоже особенная: с неё начинается выполнение программы. Когда вы запускаете собранный файл, Go находит main в пакете main и вызывает её. Всё, что между фигурными скобками { }, — тело функции, то есть инструкции, которые выполнятся по порядку сверху вниз.
Запомните пару: пакет main + функция main. Без этой пары запускать нечего — компилятор не будет знать, откуда стартовать.
fmt.Println печатает то, что вы ей передали, и переводит строку (суффикс ln — от line). Каждый вызов — с новой строки. Если передать несколько значений через запятую, они напечатаются в одну строку через пробел:
Для кнопки запуска установка не нужна. Локальный Go понадобится для многофайловых проектов, некоторых примеров с дженериками и проверки гонок. Установите Go по официальной инструкции. Терминал — окно, куда вводят команды; строку команды подтверждают клавишей Enter. Откройте терминал и выполните:
go version
Если появилась версия Go, установка доступна. Если команда не найдена, сначала завершите установку и откройте терминал заново. Создайте отдельную папку go-study через файловый менеджер и откройте её в редакторе кода. Терминал редактора должен находиться в этой папке. При необходимости перейдите в неё командой cd: например, cd "/Users/anna/Documents/Go study/go-study" в macOS или cd "C:\Users\Anna\Documents\Go study\go-study" в PowerShell. Замените пример своим путём. cd меняет рабочую папку, а кавычки сохраняют путь с пробелами.
Сохраните первый полный пример этой главы в файл main.go; проверьте, что расширение не стало .go.txt. В папке с этим файлом выполните:
go mod init example.com/go-studygo run .
Первая команда один раз создаёт go.mod — описание проекта. Домен example.com здесь часть учебного имени; создавать сайт или репозиторий не нужно. Подробнее модуль разобран в главе «Пакеты и модули». Вторая команда собирает и запускает пакет в текущей папке: точка означает «здесь». Проверка: появилась строка Привет, Go!.
Для следующей полной программы заменяйте содержимое main.go. Если оставить несколько функций main в одном пакете, сборка не начнётся. Сообщение компилятора обычно содержит имя файла и номер строки: найдите эту строку, исправьте ошибку и запустите снова. Если сообщение говорит об отсутствии go.mod, проверьте, в той ли папке находится терминал.
На своём компьютере (не в браузере) вы запускаете Go двумя основными командами. Разница между ними простая, но важная.
go run . берёт исходный код, компилирует его во временный файл, тут же запускает и выкидывает результат. Удобно во время разработки: правишь код, набираешь go run ., сразу видишь итог. Готового файла после этого не остаётся.
go run .
go build -o app компилирует код в исполняемый файл с выбранным именем app. Его можно запускать без повторной компиляции. Для другой операционной системы или архитектуры процессора программу обычно собирают отдельно.
go build -o app./app
В Windows используйте go build -o app.exe, затем .\app.exe в PowerShell. Если go build вызвать без -o, имя файла определяется именем пакета или проекта; поэтому выше мы задали его явно.
Интуиция такая: go run — это «собери и запусти разок, прямо сейчас», а go build — «собери мне готовую программу, я её сохраню и буду пользоваться». В песочнице этого учебника за вас всё запускается автоматически, поэтому команды набирать не нужно — но на реальном проекте вы будете печатать именно их.
Println хорош для быстрой печати, но часто нужно собрать строку по шаблону: вставить число в середину предложения, показать значение в нужном виде. Для этого есть fmt.Printf.
Printf принимает строку-шаблон с глаголами форматирования — это значки вроде %d или %s, на место которых подставляются ваши значения. Сами значения идут следующими аргументами, по порядку. Важная деталь: Printfне переводит строку автоматически, поэтому в конце шаблона обычно ставят \n — символ перевода строки.
Вот основные глаголы, которые покрывают почти всё на старте:
%d — целое число (от decimal);
%s — строка (от string);
%v — значение в его «обычном» виде, подходит почти для чего угодно (от value);
%T — тип значения, а не само значение (от type).
Посмотрим на %s и %d в деле:
package mainimport "fmt"func main() { name := "Аня" age := 25 fmt.Printf("Меня зовут %s, мне %d лет.\n", name, age) fmt.Printf("Через год будет %d.\n", age+1)}
Здесь %s заменился на строку "Аня", а оба %d — на числа. Порядок подстановки строго слева направо: первый глагол берёт первый аргумент после шаблона, второй — второй, и так далее.
Если вы не уверены, какой глагол подойдёт, или просто хотите «напечатай как есть», берите %v. Он универсальный:
%v напечатал и число 7, и строку товаров, и дробное 19.99 — каждое в естественном виде. На практике %v — самый частый глагол: с него удобно начинать, а на %d/%s переходить, когда нужен контроль над форматом.
Поскольку Go статически типизированный, у каждого значения есть конкретный тип. Иногда полезно посмотреть на него глазами — особенно пока вы только осваиваетесь и хотите проверить себя. Для этого есть глагол %T.
Вывод покажет: целое число имеет тип int, текст — string, дробное — float64, а true/false — bool. Это те базовые типы, с которыми вы будете работать постоянно. Подробно про них — в следующих главах; пока достаточно знать, что %T всегда подскажет, с чем вы имеете дело.
Комментарии — это заметки в коде для людей. Компилятор их полностью игнорирует, а вы (и ваши коллеги) используете, чтобы объяснить, почему написано именно так. В Go два вида комментариев.
Однострочный начинается с // и идёт до конца строки. Многострочный заключается между /* и */.
package mainimport "fmt"// main — точка входа в программу.func main() { fmt.Println("работаем") // печатаем строку в консоль /* А это длинное пояснение на несколько строк. */}
Хороший комментарий объясняет замысел, а не пересказывает очевидное. Строка i = i + 1 // увеличиваем i на единицу бесполезна: код и так это говорит. А вот // округляем вверх, иначе теряем копейку при делении — полезен, потому что объясняет причину.
Забыли импортировать fmt. Если вы используете fmt.Println, но не написали import "fmt", программа не соберётся. И наоборот: импортировали пакет, но не пользуетесь им — Go тоже выдаст ошибку. Язык строг к неиспользуемым импортам специально, чтобы код не зарастал мусором.
Перепутали Println и Printf.Println сам переводит строку, а Printf — нет. Если из Printf пропал перевод строки и вывод «слипся», скорее всего вы забыли \n в конце шаблона.
Глагол не совпал с аргументом. Если написать %d и передать туда строку, Go не подставит её молча, но и не уронит сборку — программа соберётся и запустится, просто прямо в напечатанной строке окажется специальная пометка вида %!d(string=привет). Это не падение, а сигнал «глагол и аргумент не подходят друг другу». Узнаете её — сразу поймёте, в чём дело. Когда сомневаетесь в типе, берите %v: он принимает что угодно.
Лишний или недостающий аргумент у Printf. Глаголов в шаблоне должно быть ровно столько, сколько значений вы передаёте. Тут тоже не ошибка сборки, а пометка в самом выводе: лишний аргумент даёт %!(EXTRA string=...) в конце строки, а недостающий — %!d(MISSING) на месте глагола.
Напишите полную программу без копирования готового тела main. На первой строке напечатайте имя Анна, на второй — результат 7 + 5. Затем одним вызовом Printf выведите Имя: Анна, возраст: 18 с переводом строки. Прежде чем запускать, выпишите ожидаемые три строки.
Для сборки нужны package main, import "fmt" и func main(). Почему в Println нет \n? Функция добавляет перевод строки сама; Printf использует только записанный шаблон.
Вы написали первую программу, разобрали обязательный каркас package main + func main, научились печатать через Println и форматировать вывод через Printf с глаголами %d, %s, %v, %T. Этого уже достаточно, чтобы видеть результат любой своей программы — а значит, и проверять себя дальше.
В следующей главе мы перейдём к переменным и базовым типам, которые сегодня только мелькнули в %T. Там же станет понятнее, откуда берутся int, string и float64 и как с ними работать осознанно.