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

Вывод в Rust

Ты уже не раз пользовался println!. На этой странице — другие макросы для вывода, которые тебе встретятся, и когда какой из них выбирать.

println! печатает текст и добавляет в конце перевод строки. print! делает то же самое, но перевод строки не добавляет:

fn main() {
print!("Привет, ");
print!("мир");
println!("!");
}

Вывод:

Привет, мир!
▶ Попробуй сам

Заметь: все три вызова напечатали текст в одной строке — на новую переходит только println!. На практике почти всегда используют println!, а print! полезен в основном тогда, когда строка собирается по кусочкам.

Ты уже видел {} в роли заполнителя. Заполнить его можно двумя способами: передать значение после строки или написать имя переменной прямо внутри скобок:

fn main() {
let name = "Феррис";
let age = 10;
println!("{} уже {} лет", name, age); // по позиции
println!("{name} уже {age} лет"); // прямо в строке (тот же результат)
}

Вывод:

Феррис уже 10 лет
Феррис уже 10 лет
▶ Попробуй сам

Обе строки печатают одно и то же. Стиль с именем внутри ({name}) появился чуть позже и обычно читается легче, так что по возможности выбирай его.

Иногда отформатированный текст нужен как String, а не сразу на экране — например, чтобы сохранить его или передать в другую функцию. Для этого есть format!. Он работает в точности как println!, только не печатает, а возвращает String:

fn main() {
let name = "Феррис";
let message = format!("Привет, {name}!");
println!("{message}");
}

Вывод:

Привет, Феррис!
▶ Попробуй сам

Обычный {} работает только со значениями, которые умеют показывать себя как текст: числа, строки, логические значения. Для более сложных значений, вроде кортежей или структур, {} не скомпилируется. Используй вместо него {:?} (отладочный формат, debug):

fn main() {
let point = (3, 7);
println!("{:?}", point);
}

Вывод:

(3, 7)
▶ Попробуй сам

Для больших значений есть более красивый многострочный вариант — {:#?} (pretty-print):

fn main() {
let point = (3, 7);
println!("{:#?}", point);
}

Вывод:

(
3,
7,
)
▶ Попробуй сам

Несколько приёмов форматирования, которые нужны часто:

fn main() {
let pi = 3.14159;
println!("{:.2}", pi); // 2 знака после точки -> 3.14
println!("{:5}", 42); // дополнить до ширины 5 -> " 42"
println!("{:08.2}", pi); // дополнить нулями -> 00003.14
}

Вывод:

3.14
42
00003.14
▶ Попробуй сам

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

Выравнивание текста и вывод фигурных скобок

Заголовок раздела «Выравнивание текста и вывод фигурных скобок»

Ширина работает и для текста, причём можно выбрать, к какой стороне прижимать значение. После : поставь < (влево), > (вправо) или ^ (по центру), а затем ширину. Перед ними можно указать символ-заполнитель, например -:

fn main() {
let coffee = 3.5;
let bagel = 2.25;
println!("{:-^20}", " МЕНЮ ");
println!("{:<12}{:>8}", "Товар", "Цена");
println!("{:<12}{:>8.2}", "Кофе", coffee);
println!("{:<12}{:>8.2}", "Бублик", bagel);
println!("{:<12}{:>8.2}", "Итого", coffee + bagel);
}

Вывод:

------- МЕНЮ -------
Товар Цена
Кофе 3.50
Бублик 2.25
Итого 5.75
▶ Попробуй сам

Разберём {:>8.2} по частям: > — выровнять вправо, 8 — ширина, .2 — два знака после точки. Если выровнять числа вправо, десятичные точки встанут друг под другом — поэтому так делают в чеках и таблицах. Хорошая новость для русского текста: ширина считается в символах, а не в байтах, так что кириллица выравнивается так же ровно, как латиница.

А если нужна настоящая { в выводе? Раз скобки означают «заполнитель», их нужно удвоить: {{ печатает {, а }} печатает }.

fn main() {
println!("Множество: {{{}, {}}}", 1, 2);
}

Вывод:

Множество: {1, 2}
▶ Попробуй сам

Сохрани товар "Блокнот" и цену 2.5, а затем выведи Блокнот стоит 2.50 ₽. Подсказка: {:.2} округляет до двух знаков после точки и работает прямо в строке: {price:.2}.

Показать решение
fn main() {
let item = "Блокнот";
let price = 2.5;
println!("{item} стоит {price:.2} ₽");
}

Вывод:

Блокнот стоит 2.50 ₽
▶ Попробуй сам

2. Собери метку и выведи её двумя способами

Заголовок раздела «2. Собери метку и выведи её двумя способами»

С помощью format! собери метку ferris-7 из имени "ferris" и числа 7. Выведи её один раз через {} и один раз через {:?} и найди разницу. Подсказка: format! принимает в точности те же заполнители, что и println!.

Показать решение
fn main() {
let name = "ferris";
let id = 7;
let label = format!("{name}-{id}");
println!("{label}");
println!("{label:?}");
}

Вывод:

ferris-7
"ferris-7"
▶ Попробуй сам

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

  • println! печатает с переводом строки, print! — без.
  • {} и {name} — заполнители для значений, которые умеют показывать себя через Display.
  • format! работает как println!, но не печатает, а возвращает String.
  • {:?} (и {:#?}) выводит значения для отладки, включая те, с которыми {} не справляется.
  • {:.2} округляет дроби; <, > и ^ вместе с шириной выравнивают текст; {{ и }} печатают сами скобки.

Проверь себя

1. Чем println! отличается от print!?

2. Зачем выводить кортеж через {:?}, а не через {}?

Результат: 0 / 2