Трейты (traits)
Трейты описывают общее поведение, которое могут реализовать разные типы — это интерфейсы Rust.
Трейт (trait) — набор методов, описывающих поведение; типы реализуют трейт, обещая предоставить это поведение.
Что такое трейт
Трейт — это контракт: «тип, реализующий меня, умеет делать вот это». По духу это интерфейс из других языков. Сначала объявляют трейт с сигнатурами методов, потом реализуют его для конкретных типов через impl Трейт for Тип.
trait Greet {
fn hello(&self) -> String; // только сигнатура, без тела
}
struct Russian;
struct English;
impl Greet for Russian {
fn hello(&self) -> String {
String::from("Привет")
}
}
impl Greet for English {
fn hello(&self) -> String {
String::from("Hello")
}
}
fn main() {
let r = Russian;
let e = English;
println!("{}", r.hello());
println!("{}", e.hello());
}Вывод:
Привет Hello
Дефолтные методы
Трейт может задавать реализацию метода по умолчанию. Тогда типу не обязательно его переопределять — он получит готовое поведение, но может и заменить своим.
trait Animal {
fn name(&self) -> String;
// метод с реализацией по умолчанию
fn describe(&self) -> String {
format!("Это {}", self.name())
}
}
struct Dog;
impl Animal for Dog {
fn name(&self) -> String {
String::from("собака")
}
// describe не переопределяем — берём дефолтный
}
fn main() {
let d = Dog;
println!("{}", d.describe());
}Вывод:
Это собака
Трейты как ограничения
Главная польза трейтов — в обобщённом коде. Функция может принимать «любой тип, который реализует трейт Greet». Это записывают через impl Trait в параметре или через ограничение <T: Trait>.
trait Greet {
fn hello(&self) -> String;
}
struct Russian;
impl Greet for Russian {
fn hello(&self) -> String { String::from("Привет") }
}
// принимаем любой тип, реализующий Greet
fn announce(g: &impl Greet) {
println!("Говорит: {}", g.hello());
}
fn main() {
announce(&Russian);
}Вывод:
Говорит: Привет
Так трейты дают полиморфизм: одна функция работает с любым типом, который умеет нужное поведение, и компилятор проверяет это заранее.
derive — реализация трейтов автоматом
Многие стандартные трейты Rust умеет реализовать за вас. Атрибут #[derive(...)] над структурой автоматически добавляет нужное поведение — без ручного impl.
#[derive(Debug, Clone, PartialEq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let a = Point { x: 1, y: 2 };
let b = a.clone(); // Clone
println!("{:?}", a); // Debug — печать через {:?}
println!("равны: {}", a == b); // PartialEq — сравнение через ==
}Вывод:
Point { x: 1, y: 2 }
равны: trueИтог
- Трейт — это интерфейс Rust: контракт поведения, который типы реализуют через
impl Trait for Тип. - Трейты могут давать дефолтные методы и использоваться как ограничения в обобщённом коде.
#[derive(...)]реализует стандартные трейты (Debug,Clone,PartialEq) автоматически.