Ввод/вывод. Работа с fmt
Учимся выводить текст на экран, форматировать данные и читать ввод от пользователя
В прошлом уроке мы научились создавать переменные и познакомились с основными типами данных: числа, строки, логические значения. Но программа, которая просто хранит данные внутри себя и ничего не показывает пользователю, бесполезна. Представьте калькулятор, который считает результат, но не выводит его на экран. Или навигатор, который знает маршрут, но молчит. Любая программа должна уметь две вещи: показывать информацию пользователю (вывод) и получать от него данные (ввод). Сегодня мы разберём пакет fmt — главный инструмент Go для ввода и вывода. А в конце урока напишем мини-игру «Угадай число».
📦 Что такое пакет fmt
Название fmt — это сокращение от слова format (форматирование). Этот пакет входит в стандартную библиотеку Go, а значит его не нужно устанавливать отдельно — он доступен сразу «из коробки». Вы уже видели fmt в программе «Hello, World!», когда писали fmt.Println("Hello, World!").
Пакет fmt содержит функции для двух задач:
- Вывод — отображение текста и данных на экране (
Println,Printf,Print) - Ввод — чтение данных, которые пользователь вводит с клавиатуры (
Scan,Scanln,Scanf)
Чтобы использовать fmt, нужно импортировать его в начале файла. Это вы уже умеете:
package main
import "fmt"
func main() {
fmt.Println("Привет!")
}
Давайте разберём каждую функцию подробно.
🖨 fmt.Println — простой вывод
Println расшифровывается как Print Line — «напечатать строку». Это самая простая и часто используемая функция вывода. Она печатает то, что вы ей передали, и автоматически переходит на новую строку.
package main
import "fmt"
func main() {
fmt.Println("Привет, мир!")
fmt.Println("Меня зовут Go.")
fmt.Println("Мне нравится программировать.")
}
Результат в терминале:
Привет, мир!
Меня зовут Go.
Мне нравится программировать.
Обратите внимание: каждый Println выводит текст на отдельной строке. Это потому что функция автоматически добавляет символ перевода строки в конце.
Println может принимать сразу несколько значений через запятую. Она разделит их пробелами:
name := "Алексей"
age := 25
fmt.Println("Имя:", name, "Возраст:", age)
Результат:
Имя: Алексей Возраст: 25
Удобно: не нужно самостоятельно вставлять пробелы между значениями — Println делает это за вас. Можно передавать строки, числа, логические значения — вообще любые типы данных. Go сам поймёт, как их напечатать.
📄 fmt.Print — вывод без перехода на новую строку
Функция Print работает почти так же, как Println, но с одним отличием — она не добавляет перевод строки в конце. Это значит, что следующий вывод продолжится на той же строке:
fmt.Print("Привет, ")
fmt.Print("мир!")
fmt.Println() // пустой Println просто переводит строку
fmt.Print("Новая строка")
Результат:
Привет, мир!
Новая строка
Когда это полезно? Например, когда вы хотите вывести приглашение для ввода, чтобы пользователь печатал ответ на той же строке: fmt.Print("Введите ваше имя: "). Курсор останется сразу после двоеточия, и пользователь начнёт вводить текст рядом.
🎯 fmt.Printf — форматированный вывод
А вот это самая мощная функция вывода. Printf расшифровывается как Print Formatted — «напечатать с форматированием». Она позволяет точно контролировать, как именно данные будут выглядеть на экране.
Идея простая: вы пишете шаблон строки, а места, куда нужно подставить значения, отмечаете специальными символами — глаголами форматирования (format verbs). Они всегда начинаются со знака %.
name := "Мария"
age := 30
fmt.Printf("Меня зовут %s, мне %d лет.\n", name, age)
Результат:
Меня зовут Мария, мне 30 лет.
Что здесь произошло? Go взял шаблон "Меня зовут %s, мне %d лет.\n" и заменил %s на значение переменной name (строку «Мария»), а %d — на значение переменной age (число 30). Символ \n в конце — это символ перевода строки. В отличие от Println, функция Printf сама не добавляет перевод строки, поэтому нужно делать это вручную через \n.
💡 Подсказка: обратите внимание на \n в конце строки формата. Если его не поставить, следующий вывод или приглашение терминала начнётся сразу после текста — без перехода на новую строку. Это частая ошибка у новичков. Запомните: Printf ничего не добавляет сам — что написали, то и получите.
🔤 Глаголы форматирования: %d, %s, %f, %v и другие
Каждый глагол говорит Go, какой тип данных подставлять и как его отображать. Давайте разберём самые важные.
%d — целое число
Используется для вывода целых чисел (int, int64 и т.д.). Буква «d» — от слова «decimal» (десятичное).
score := 95
fmt.Printf("Ваш результат: %d баллов\n", score)
// Ваш результат: 95 баллов
%s — строка
Используется для вывода строк (string). Буква «s» — от слова «string».
city := "Москва"
fmt.Printf("Город: %s\n", city)
// Город: Москва
%f — дробное число
Используется для вывода чисел с плавающей точкой (float64, float32). Буква «f» — от слова «float». По умолчанию выводит 6 знаков после запятой.
pi := 3.14159265
fmt.Printf("Число Пи: %f\n", pi)
// Число Пи: 3.141593
Шесть знаков после запятой — это многовато. Можно указать нужную точность, вставив число между % и f:
pi := 3.14159265
fmt.Printf("Пи (2 знака): %.2f\n", pi) // 3.14
fmt.Printf("Пи (4 знака): %.4f\n", pi) // 3.1416
fmt.Printf("Пи (0 знаков): %.0f\n", pi) // 3
Запись %.2f означает: «выведи дробное число с двумя знаками после точки». Это очень полезно при работе с деньгами, процентами и любыми числами, где нужна определённая точность.
%v — универсальный глагол
Буква «v» — от слова «value» (значение). Этот глагол подходит для любого типа данных. Go сам определит, как лучше вывести значение. Когда лень думать, какой глагол использовать — берите %v.
name := "Анна"
age := 22
height := 1.68
student := true
fmt.Printf("Имя: %v\n", name) // Имя: Анна
fmt.Printf("Возраст: %v\n", age) // Возраст: 22
fmt.Printf("Рост: %v\n", height) // Рост: 1.68
fmt.Printf("Студент: %v\n", student) // Студент: true
%T — тип переменной
Иногда хочется узнать, какого типа переменная. Глагол %T выводит именно тип, а не значение. Это удобно для отладки.
x := 42
y := 3.14
z := "hello"
fmt.Printf("x: тип=%T, значение=%v\n", x, x) // x: тип=int, значение=42
fmt.Printf("y: тип=%T, значение=%v\n", y, y) // y: тип=float64, значение=3.14
fmt.Printf("z: тип=%T, значение=%v\n", z, z) // z: тип=string, значение=hello
💡 Подсказка: если вы используете не тот глагол (например, %d для строки), Go не выдаст ошибку при компиляции, но результат может быть странным. Поэтому следите за соответствием: %d для целых чисел, %s для строк, %f для дробных чисел. А если сомневаетесь — используйте %v, он работает с чем угодно.
📊 Шпаргалка по глаголам
Вот сводная таблица глаголов, которые вам понадобятся чаще всего. Не нужно заучивать всё наизусть — просто знайте, что такая таблица есть, и возвращайтесь к ней по мере необходимости.
%d — целое число (42, -7, 0)
%s — строка ("Привет")
%f — дробное число (3.14); %.2f — с точностью 2 знака
%v — любое значение (Go сам выберет формат)
%T — тип переменной (int, string, float64)
%t — логическое значение (true, false)
%% — вывести сам символ процента (%)
\n — перевод строки (не глагол, а спецсимвол)
🧪 Практика: комбинируем разные способы вывода
Давайте напишем программу, которая выводит информацию о товаре в интернет-магазине. Здесь мы используем все три функции вывода и несколько глаголов форматирования:
package main
import "fmt"
func main() {
// Информация о товаре
product := "Наушники Sony WH-1000XM5"
price := 29990.00
discount := 15 // процент скидки
inStock := true
// Вычисляем цену со скидкой
finalPrice := price * (1 - float64(discount) / 100)
// Выводим красивую карточку товара
fmt.Println("===========================")
fmt.Printf("Товар: %s\n", product)
fmt.Printf("Цена: %.2f руб.\n", price)
fmt.Printf("Скидка: %d%%\n", discount)
fmt.Printf("Итого: %.2f руб.\n", finalPrice)
fmt.Printf("В наличии: %t\n", inStock)
fmt.Println("===========================")
}
Результат:
===========================
Товар: Наушники Sony WH-1000XM5
Цена: 29990.00 руб.
Скидка: 15%
Итого: 25491.50 руб.
В наличии: true
===========================
Обратите внимание на %d%% в строке со скидкой. Первый %d — это глагол для числа 15. А %% — это способ напечатать сам символ процента. Если написать просто %, Go подумает, что это начало нового глагола. Поэтому два процента подряд — %% — означают «просто выведи знак %».
⌨️ fmt.Scan — читаем ввод от пользователя
До сих пор все наши программы «говорили», но не «слушали». Пора научить программу получать данные от пользователя. Для этого используются функции fmt.Scan и fmt.Scanln.
Принцип простой: вы создаёте переменную, а затем передаёте в функцию Scan указатель на неё (через символ &). Программа остановится и будет ждать, пока пользователь что-нибудь введёт с клавиатуры и нажмёт Enter. Введённое значение запишется в вашу переменную.
package main
import "fmt"
func main() {
var name string
fmt.Print("Как вас зовут? ")
fmt.Scan(&name)
fmt.Printf("Приятно познакомиться, %s!\n", name)
}
Как это работает:
var name string— создаём переменнуюnameтипа строка (пока пустую)fmt.Print("Как вас зовут? ")— выводим вопрос (без перевода строки, чтобы пользователь печатал на той же строке)fmt.Scan(&name)— программа останавливается и ждёт ввод. Пользователь пишет, например, «Андрей» и нажимает Enter. Значение «Андрей» записывается в переменнуюnamefmt.Printf(...)— выводим приветствие с именем пользователя
Пример работы в терминале:
Как вас зовут? Андрей
Приятно познакомиться, Андрей!
💡 Подсказка: символ & перед переменной — это оператор взятия адреса. Пока не вдавайтесь в детали: просто запомните, что при использовании Scan перед переменной всегда нужно ставить &. Без него программа не скомпилируется. Мы подробнее разберём указатели позже в курсе.
🔢 Чтение чисел от пользователя
fmt.Scan автоматически определяет тип переменной и пытается преобразовать ввод пользователя в нужный тип. Если переменная — int, Go ожидает от пользователя целое число. Если float64 — дробное.
package main
import "fmt"
func main() {
var age int
fmt.Print("Сколько вам лет? ")
fmt.Scan(&age)
fmt.Printf("Через 10 лет вам будет %d!\n", age + 10)
}
Пример работы:
Сколько вам лет? 25
Через 10 лет вам будет 35!
А вот пример с дробными числами:
package main
import "fmt"
func main() {
var weight float64
fmt.Print("Ваш вес (кг): ")
fmt.Scan(&weight)
fmt.Printf("Ваш вес в фунтах: %.1f\n", weight * 2.205)
}
Пример работы:
Ваш вес (кг): 70.5
Ваш вес в фунтах: 155.5
Можно читать несколько значений за один вызов Scan:
var width, height float64
fmt.Print("Введите ширину и высоту: ")
fmt.Scan(&width, &height)
fmt.Printf("Площадь: %.2f\n", width * height)
В этом случае пользователь вводит два числа через пробел (или каждое на отдельной строке), а Scan запишет первое в width, второе в height.
📝 fmt.Scanln — чтение до конца строки
Функция fmt.Scanln (Scan Line) похожа на Scan, но с одним важным отличием: она прекращает чтение на символе перевода строки (когда пользователь нажимает Enter). Это значит, что все значения должны быть на одной строке.
var firstName, lastName string
fmt.Print("Введите имя и фамилию: ")
fmt.Scanln(&firstName, &lastName)
fmt.Printf("Добро пожаловать, %s %s!\n", firstName, lastName)
Пример работы:
Введите имя и фамилию: Иван Петров
Добро пожаловать, Иван Петров!
В чём разница между Scan и Scanln на практике? Scan читает значения, разделённые пробелами или переводами строк, и может «перетекать» на следующие строки. А Scanln читает только текущую строку. Для простых программ разница невелика, но Scanln обычно ведёт себя предсказуемее, когда вы читаете данные порциями — по одной строке за раз.
💡 Подсказка: для большинства задач в этом курсе используйте fmt.Scan — он проще. Переходите на fmt.Scanln, если сталкиваетесь со странным поведением при нескольких вызовах Scan подряд. Также существует fmt.Scanf (с шаблоном формата), но он используется значительно реже — мы его разберём, когда он понадобится.
🚧 Частые ошибки при вводе/выводе
Разберём типичные ошибки, с которыми сталкиваются новички, чтобы вы могли их избежать.
Забыли & перед переменной в Scan
Это самая популярная ошибка. Без & программа не скомпилируется.
var age int
fmt.Scan(age) // ОШИБКА! Не скомпилируется
fmt.Scan(&age) // Правильно
Несовпадение количества глаголов и значений в Printf
Количество глаголов (%d, %s и т.д.) в шаблоне должно совпадать с количеством переданных значений. Иначе будет предупреждение или некорректный вывод.
name := "Ира"
age := 20
// ПЛОХО: два глагола, но передано одно значение
fmt.Printf("Имя: %s, возраст: %d\n", name)
// ХОРОШО: два глагола, два значения
fmt.Printf("Имя: %s, возраст: %d\n", name, age)
Пользователь ввёл не то, что ожидалось
Если переменная типа int, а пользователь ввёл текст (например, «abc»), Scan вернёт ошибку и переменная останется с нулевым значением (0 для int). Пока мы не обрабатываем ошибки — это тема будущих уроков. Просто имейте это в виду и вводите правильные данные при тестировании.
Забыли \n в Printf
Printf не добавляет перевод строки автоматически. Если в конце шаблона нет \n, следующий вывод или приглашение терминала «прилипнет» к вашему тексту.
fmt.Printf("Привет")
fmt.Printf("Мир")
// Результат: ПриветМир (всё слиплось!)
fmt.Printf("Привет\n")
fmt.Printf("Мир\n")
// Результат:
// Привет
// Мир
🎮 Практика: программа «Угадай число»
Теперь давайте объединим всё, что мы сегодня узнали, в одну мини-игру. Программа загадает число, а пользователь попытается его угадать. Пока у нас нет циклов (мы их изучим в уроке 2.5), поэтому пользователь получит только одну попытку. Также у нас пока нет конструкции if/else (это следующий урок), поэтому мы просто покажем загаданное число и ответ пользователя, чтобы он сам сравнил.
Но подождите — как программе «загадать» число? Для этого нам понадобится пакет math/rand, который генерирует случайные числа. Давайте сразу посмотрим готовую программу, а потом разберём каждую строку:
package main
import (
"fmt"
"math/rand"
)
func main() {
// Загадываем случайное число от 1 до 10
secret := rand.IntN(10) + 1
fmt.Println("=== Угадай число ===")
fmt.Println("Я загадал число от 1 до 10.")
fmt.Println("У тебя одна попытка!")
fmt.Println()
// Читаем ответ пользователя
var guess int
fmt.Print("Твоё число: ")
fmt.Scan(&guess)
// Выводим результат
fmt.Println()
fmt.Printf("Ты ввёл: %d\n", guess)
fmt.Printf("Я загадал: %d\n", secret)
fmt.Println()
fmt.Println("Совпало? Проверь сам!")
fmt.Println("(В уроке 2.4 мы научим программу")
fmt.Println("проверять это автоматически)")
}
Пример работы программы:
=== Угадай число ===
Я загадал число от 1 до 10.
У тебя одна попытка!
Твоё число: 7
Ты ввёл: 7
Я загадал: 3
Совпало? Проверь сам!
(В уроке 2.4 мы научим программу
проверять это автоматически)
Давайте разберём новые моменты:
Импорт нескольких пакетов
Когда нужно импортировать больше одного пакета, используем скобки: import ("fmt" "math/rand"). Каждый пакет — на отдельной строке.
rand.IntN(10) + 1
rand.IntN(10) генерирует случайное число от 0 до 9 (включительно). Мы прибавляем 1, чтобы получить диапазон от 1 до 10. Почему от нуля? Так принято в программировании — отсчёт чаще всего начинается с нуля.
fmt.Println() без аргументов
Вызов fmt.Println() без текста просто выводит пустую строку. Это удобно для визуального разделения блоков текста в терминале.
💡 Подсказка: каждый раз при запуске программы rand.IntN будет генерировать разные числа. В старых версиях Go (до 1.20) нужно было вручную инициализировать генератор случайных чисел через rand.Seed, но начиная с Go 1.20 это происходит автоматически. Так что просто вызывайте rand.IntN — и всё будет работать.
🧑💻 Бонус: программа «Визитка»
Напоследок — ещё одна полноценная программа, которая собирает информацию от пользователя и красиво её выводит. Она использует все функции, которые мы сегодня изучили:
package main
import "fmt"
func main() {
var name string
var age int
var city string
var height float64
fmt.Println("=== Генератор визиток ===")
fmt.Println()
fmt.Print("Ваше имя: ")
fmt.Scan(&name)
fmt.Print("Ваш возраст: ")
fmt.Scan(&age)
fmt.Print("Ваш город: ")
fmt.Scan(&city)
fmt.Print("Ваш рост (м): ")
fmt.Scan(&height)
// Выводим визитку
fmt.Println()
fmt.Println("+--------------------------+")
fmt.Printf("| Имя: %-15s |\n", name)
fmt.Printf("| Возраст: %-14d |\n", age)
fmt.Printf("| Город: %-15s |\n", city)
fmt.Printf("| Рост: %-15.2f |\n", height)
fmt.Println("+--------------------------+")
}
Пример работы:
=== Генератор визиток ===
Ваше имя: Алексей
Ваш возраст: 28
Ваш город: Казань
Ваш рост (м): 1.82
+--------------------------+
| Имя: Алексей |
| Возраст: 28 |
| Город: Казань |
| Рост: 1.82 |
+--------------------------+
Здесь есть новый трюк: %-15s. Число 15 — это ширина поля (минимальное количество символов). Минус перед числом означает выравнивание по левому краю. Благодаря этому столбцы визитки получаются ровными. Не обязательно запоминать это сейчас — просто знайте, что Printf позволяет управлять выравниванием и шириной вывода.
📌 Задание для самостоятельной работы
Чтобы закрепить материал, попробуйте написать эти программы самостоятельно:
Задание 1. Напишите программу, которая спрашивает у пользователя длину и ширину комнаты (в метрах, дробные числа) и выводит её площадь с двумя знаками после запятой.
Подсказка: площадь = длина * ширина. Для вывода используйте %.2f.
Задание 2. Напишите программу-конвертер температуры. Пользователь вводит температуру в Цельсиях, а программа выводит её в Фаренгейтах.
Подсказка: формула: F = C * 9/5 + 32. Используйте float64.
Задание 3. Напишите программу, которая спрашивает имя пользователя, год его рождения и выводит сообщение: «Привет, [имя]! В 2026 году тебе будет [возраст] лет.»
Подсказка: возраст = 2026 - год_рождения. Для красивого вывода используйте Printf.
📋 Итоги урока
fmt.Println— выводит текст и автоматически переходит на новую строкуfmt.Print— выводит текст без перевода строки (удобно для приглашений ввода)fmt.Printf— форматированный вывод с глаголами:%d(целое число),%s(строка),%f(дробное),%v(любое значение),%T(тип)%.2f— вывод дробного числа с заданной точностью (2 знака после точки)fmt.Scan(&переменная)— читает ввод пользователя и записывает в переменную (не забывайте&!)fmt.Scanln— аналогScan, но читает только текущую строку- Пакет
math/randпозволяет генерировать случайные числа - Мы написали мини-игру «Угадай число» — в будущих уроках мы добавим ей проверку ответа и несколько попыток
В следующем уроке мы разберём операторы и выражения: арифметические (+, -, *, /, %), сравнения (==, !=, <, >) и логические (&&, ||, !). Вы узнаете, как Go считает, сравнивает и принимает решения на основе данных. А в качестве практики напишем программу-калькулятор с выбором операции. До встречи в уроке 2.3!