| Тип | Пример вывода | Примечания |
i8, i16, i32, i64, i128, isize | -42, 123 | Целочисленные со знаком |
u8, u16, u32, u64, u128, usize | 42, 255 | Целочисленные без знака |
f32, f64 | 3.14, -0.001 | Числа с плавающей точкой |
bool | true, false | Логические значения |
char | 'a', '🦀' | Символы Unicode |
&str, String | "hello", "world" | Строки |
Option<T> | Some(42), None | Если T реализует Display |
Result<T, E> | Ok(42), Err("error") | Если T и E реализуют Display |
() | () | Пустой кортеж |
&T | То же, что T | Ссылки |
Box<T> | То же, что T | Умный указатель |
Rc<T>, Arc<T> | То же, что T | Счетчики ссылок |
Vec<T> | [1, 2, 3] | Если T реализует Display |
[T; N] | [1, 2, 3] | Массивы |
Cell<T>, RefCell<T> | То же, что T | Внутренняя изменяемость |
Mutex<T>, RwLock<T> | То же, что T | Синхронизация |
Path, PathBuf | /home/user/file.txt | Пути файловой системы |
IpAddr, SocketAddr | 192.168.1.1:8080 | Сетевые адреса |
Duration | 2.5s, 500ms | Промежутки времени |
SystemTime, Instant | Временные метки | Время системы |
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("Точка: {}", p); // Точка: (10, 20)
}
use std::fmt;
struct Color {
red: u8,
green: u8,
blue: u8,
}
impl fmt::Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RGB({}, {}, {}) 0x{:02X}{:02X}{:02X}",
self.red, self.green, self.blue,
self.red, self.green, self.blue)
}
}
fn main() {
let color = Color { red: 255, green: 128, blue: 0 };
println!("{}", color); // RGB(255, 128, 0) 0xFF8000
}
use std::fmt;
enum HttpStatus {
Ok,
NotFound,
InternalServerError,
}
impl fmt::Display for HttpStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HttpStatus::Ok => write!(f, "200 OK"),
HttpStatus::NotFound => write!(f, "404 Not Found"),
HttpStatus::InternalServerError => write!(f, "500 Internal Server Error"),
}
}
}
fn main() {
let status = HttpStatus::NotFound;
println!("Статус: {}", status); // Статус: 404 Not Found
}
use std::fmt;
struct Pair<T> {
first: T,
second: T,
}
impl<T: fmt::Display> fmt::Display for Pair<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.first, self.second)
}
}
fn main() {
let int_pair = Pair { first: 1, second: 2 };
let str_pair = Pair { first: "hello", second: "world" };
println!("{}", int_pair); // (1, 2)
println!("{}", str_pair); // (hello, world)
}
// В Cargo.toml:
// [dependencies]
// derive_more = "1.0"
use derive_more::Display;
#[derive(Display)]
#[display(fmt = "Пользователь: {} ({} лет)", name, age)]
struct User {
name: String,
age: u32,
}
fn main() {
let user = User { name: "Анна".to_string(), age: 25 };
println!("{}", user); // Пользователь: Анна (25 лет)
}
use std::fmt;
struct Temperature {
celsius: f64,
}
impl fmt::Display for Temperature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let precision = f.precision().unwrap_or(1);
write!(f, "{:.precision$}°C", self.celsius, precision = precision)
}
}
fn main() {
let temp = Temperature { celsius: 23.456 };
println!("{}", temp); // 23.5°C
println!("{:.2}", temp); // 23.46°C
println!("{:.0}", temp); // 23°C
}
use std::fmt;
// Для owned типа
struct Person {
name: String,
age: u8,
}
impl fmt::Display for Person {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} - {} лет", self.name, self.age)
}
}
// Для типа с ссылками
struct Name<'a> {
first: &'a str,
last: &'a str,
}
impl<'a> fmt::Display for Name<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.first, self.last)
}
}
fn main() {
let person = Person { name: "Иван".to_string(), age: 30 };
let name = Name { first: "Мария", last: "Петрова" };
println!("{}", person); // Иван - 30 лет
println!("{}", name); // Мария Петрова
}
use std::fmt;
struct BlogPost {
title: String,
author: String,
content: String,
likes: u32,
}
impl fmt::Display for BlogPost {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "📝 {}", self.title)?;
writeln!(f, "✍️ Автор: {}", self.author)?;
writeln!(f)?;
// Обрезаем контент для краткости
let preview = if self.content.len() > 100 {
&self.content[..100]
} else {
&self.content
};
write!(f, "{}{}", preview, if self.content.len() > 100 { "..." } else { "" })?;
writeln!(f)?;
write!(f, "❤️ {} лайков", self.likes)
}
}
fn main() {
let post = BlogPost {
title: "Мой первый пост в Rust".to_string(),
author: "Алексей".to_string(),
content: "Сегодня я изучал трейт Display в Rust. Это очень полезный трейт для форматирования вывода...".to_string(),
likes: 42,
};
println!("{}", post);
}
Вывод:
📝 Мой первый пост в Rust
✍️ Автор: Алексей
Сегодня я изучал трейт Display в Rust. Это очень полезный трейт для форматирования вывода...
❤️ 42 лайков
- Требуется только один метод -
fmt
- Возвращает
fmt::Result - специализированный Result для форматирования
- Использует
Formatter для гибкого форматирования
- Может использовать все возможности форматирования (ширина, точность, выравнивание)
- Должен быть всегда успешным (в отличие от Debug, который может паниковать)
#![allow(unused)]
fn main() {
pub type Result = result::Result<(), Error>;
}
| Характеристика | Описание |
| Тип | Псевдоним для Result<(), std::fmt::Error> |
| Успех | Ok(()) - форматирование выполнено |
| Ошибка | Err(Error) - ошибка форматирования |
| Error тип | std::fmt::Error - нумератор без вариантов |
| Использование | Всегда через ? оператор |
#![allow(unused)]
fn main() {
use std::fmt;
impl fmt::Display for MyType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// При ошибке автоматически возвращается Err(Error)
write!(f, "Значение: {}", self.value)?;
Ok(()) // Явный возврат успеха
}
}
}
| Метод | Назначение | Пример |
write_str(&mut self, s: &str) | Запись строки | f.write_str("hello")? |
write_fmt(&mut self, args: Arguments) | Запись форматирования | f.write_fmt(format_args!("{}", x))? |
| Метод | Возвращает | Описание |
width() | Option<usize> | Запрошенная ширина поля |
precision() | Option<usize> | Запрошенная точность |
align() | Option<Alignment> | Выравнивание |
fill() | char | Символ-заполнитель |
sign_plus() | bool | Показывать ли + для положительных |
sign_minus() | bool | Всегда true |
alternate() | bool | Альтернативный формат # |
sign_aware_zero_pad() | bool | Заполнение нулями с учетом знака |
#![allow(unused)]
fn main() {
pub enum Alignment {
Left, // <
Center, // ^
Right, // >
}
}
#![allow(unused)]
fn main() {
use std::fmt;
struct SafeDisplay(String);
impl fmt::Display for SafeDisplay {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Каждый write! возвращает fmt::Result
write!(f, "Safe: ")?; // Если ошибка - сразу возврат
write!(f, "{}", self.0)?; // Если ошибка - сразу возврат
Ok(()) // Все успешно
}
}
}
use std::fmt;
struct FlexibleNumber(i32);
impl fmt::Display for FlexibleNumber {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match (f.width(), f.precision()) {
(Some(w), Some(p)) => write!(f, "{:0>width$.prec$}", self.0, width = w, prec = p),
(Some(w), None) => write!(f, "{:>width$}", self.0, width = w),
(None, Some(p)) => write!(f, "{:.prec$}", self.0, prec = p),
(None, None) => write!(f, "{}", self.0),
}
}
}
fn main() {
let num = FlexibleNumber(42);
println!("{}", num); // 42
println!("{:5}", num); // 42
println!("{:05}", num); // 00042
println!("{:.2}", num); // 42.00
}
#![allow(unused)]
fn main() {
use std::fmt;
struct DecoratedText(&'static str);
impl fmt::Display for DecoratedText {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let width = f.width().unwrap_or(10);
let fill = f.fill();
match f.align() {
Some(fmt::Alignment::Left) => {
write!(f, "{:<width$}", self.0, width = width)
},
Some(fmt::Alignment::Center) => {
write!(f, "{:^width$}", self.0, width = width)
},
Some(fmt::Alignment::Right) => {
write!(f, "{:>width$}", self.0, width = width)
},
None => write!(f, "{}", self.0),
}
}
}
}
use std::fmt;
struct SmartFloat(f64);
impl fmt::Display for SmartFloat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let precision = f.precision().unwrap_or(2);
if f.alternate() {
// Альтернативный формат с #
write!(f, "≈{:.prec$}", self.0, prec = precision)
} else if f.sign_plus() {
// Всегда показывать знак
write!(f, "{:+.prec$}", self.0, prec = precision)
} else {
// Стандартный формат
write!(f, "{:.prec$}", self.0, prec = precision)
}
}
}
fn main() {
let num = SmartFloat(3.14159);
println!("{}", num); // 3.14
println!("{:#}", num); // ≈3.14
println!("{:+}", num); // +3.14
println!("{:.4}", num); // 3.1416
}
- "Писатель" с информацией о форматировании
- Небуферизованный - пишет напрямую в выходной поток
- Предоставляет контекст форматирования (ширина, точность, выравнивание)
- Безопасный - гарантирует корректное UTF-8
- Специализированный Result только для форматирования
- Ошибка всегда одна -
fmt::Error (пустой enum)
- Идиоматическое использование - распространение через
?
- Не требует обработки ошибок - обычно просто пробрасывается
#![allow(unused)]
fn main() {
impl fmt::Display for MyType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.field1)?; // ? для распространения ошибок
write!(f, " - ")?;
write!(f, "{}", self.field2)?;
Ok(()) // Явный возврат успеха в конце
}
}
}