Как получить строковое представление варианта перечисления (enum) в Rust?
1. Реализация трейта Display — самый правильный способ
Самый идиоматичный и гибкий подход — реализовать трейт std::fmt::Display для вашего перечисления. Это позволяет контролировать вывод и использовать макросы println!, format! и write! напрямую.
use std::fmt;
enum OrderStatus {
Pending,
Processing,
Shipped,
Delivered,
Cancelled,
}
impl fmt::Display for OrderStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OrderStatus::Pending => write!(f, "Pending"),
OrderStatus::Processing => write!(f, "Processing"),
OrderStatus::Shipped => write!(f, "Shipped"),
OrderStatus::Delivered => write!(f, "Delivered"),
OrderStatus::Cancelled => write!(f, "Cancelled"),
}
}
}
fn main() {
let status = OrderStatus::Shipped;
println!("Статус заказа: {}", status);
// Вывод: Статус заказа: Shipped
}
Преимущества:
- Полный контроль над форматированием
- Можно добавлять дополнительные данные (например, для вариантов с полями)
- Работает со всеми макросами форматирования
- Нулевые накладные расходы во время выполнения
2. Использование крейта strum — для ленивых
Если у вас много вариантов или вы часто конвертируете enum в строку, используйте крейт strum с макросом Display. Добавьте в Cargo.toml:
[dependencies]
strum = { version = "0.26", features = ["derive"] }
Теперь код становится однострочным:
use strum::Display;
#[derive(Display)]
enum OrderStatus {
Pending,
Processing,
Shipped,
Delivered,
Cancelled,
}
fn main() {
let status = OrderStatus::Delivered;
println!("{}", status); // "Delivered"
}
Важно: По умолчанию strum::Display использует snake_case для имён. Если нужно сохранить точное имя варианта, используйте атрибут #[strum(serialize_all = "PascalCase")].
3. Метод as_ref() — только для C-подобных enum
Если ваше перечисление не содержит данных (как в примере), вы можете использовать трюк с приведением к строковому срезу через as_ref() и std::mem::discriminant. Но это сложнее и менее читаемо, поэтому я не рекомендую новичкам.
4. Когда использовать какой подход?
- Display вручную — когда нужно разное форматирование для разных вариантов или есть вложенные данные.
- strum — для простых enum без данных, когда лень писать match.
- Debug — только для отладки, не для пользовательского вывода.
Совет: Всегда старайтесь реализовать Display для enum, которые будут выводиться пользователю. Это улучшает читаемость кода и делает его более идиоматичным для Rust.
Альтернатива: функция as_str() и макрос для автоматической генерации
Если вы не хотите подключать внешние крейты, но хотите избежать ручного написания match, можно написать простой макрос для генерации метода as_str():
macro_rules! enum_to_str {
($name:ident { $($variant:ident),* $(,)? }) => {
impl $name {
fn as_str(&self) -> &'static str {
match self {
$( $name::$variant => stringify!($variant), )*
}
}
}
};
}
enum OrderStatus {
Pending,
Processing,
Shipped,
Delivered,
Cancelled,
}
enum_to_str!(OrderStatus { Pending, Processing, Shipped, Delivered, Cancelled });
fn main() {
let s = OrderStatus::Shipped.as_str();
println!("{}", s); // "Shipped"
}
Плюсы: Нет зависимостей, полный контроль, нулевой оверхед.
Минусы: Нужно поддерживать список вариантов в макросе вручную, не работает с enum, содержащими данные.
Для enum с данными лучше использовать Display или strum, так как макрос не сможет корректно обработать поля.
Ответов пока нет.
Войдите чтобы оставить ответ