Что такое Traits
Trait — это способ определить общее поведение для типов. Аналог интерфейсов в других языках.
▸Определение trait
1trait Summary {2 fn summarize(&self) -> String;34 // Метод по умолчанию5 fn preview(&self) -> String {6 format!("{}...", &self.summarize()[..50])7 }8}
▸Реализация trait
1struct Article {2 title: String,3 author: String,4 content: String,5}67impl Summary for Article {8 fn summarize(&self) -> String {9 format!("{}, by {} - {}", self.title, self.author, &self.content[..100])10 }11}1213struct Tweet {14 username: String,15 content: String,16}1718impl Summary for Tweet {19 fn summarize(&self) -> String {20 format!("{}: {}", self.username, self.content)21 }22}
Generics
▸Функции с generics
1fn largest<T: PartialOrd>(list: &[T]) -> &T {2 let mut largest = &list[0];3 for item in &list[1..] {4 if item > largest {5 largest = item;6 }7 }8 largest9}1011fn main() {12 let numbers = vec![34, 50, 25, 100, 65];13 println!("Largest: {}", largest(&numbers));14}
▸Структуры с generics
1struct Point<T> {2 x: T,3 y: T,4}56// Разные типы7struct Point2<T, U> {8 x: T,9 y: U,10}1112impl<T> Point<T> {13 fn x(&self) -> &T {14 &self.x15 }16}1718// Методы только для определённых типов19impl Point<f32> {20 fn distance_from_origin(&self) -> f32 {21 (self.x.powi(2) + self.y.powi(2)).sqrt()22 }23}
Trait Bounds
▸Базовый синтаксис
1// Через where2fn process<T>(item: T) -> String3where4 T: Summary + Display,5{6 format!("{}: {}", item.summarize(), item)7}89// Инлайн10fn process<T: Summary + Display>(item: T) -> String {11 format!("{}: {}", item.summarize(), item)12}
▸Ограничения
1use std::fmt::{Debug, Display};23fn print_if_display<T: Display + Debug>(item: T) {4 println!("Display: {}", item);5 println!("Debug: {:?}", item);6}78// Множественные bounds9fn complex_function<T, U>(t: T, u: U) -> String10where11 T: Display + Clone,12 U: Debug + Default,13{14 format!("{}: {:?}", t, u)15}
Associated Types
1trait Iterator {2 type Item;34 fn next(&mut self) -> Option<Self::Item>;5}67struct Counter {8 current: u32,9 max: u32,10}1112impl Iterator for Counter {13 type Item = u32;1415 fn next(&mut self) -> Option<Self::Item> {16 if self.current < self.max {17 self.current += 1;18 Some(self.current)19 } else {20 None21 }22 }23}
Blanket Implementations
1// Реализация trait для всех типов, реализующих другой trait2impl<T: Display> ToString for T {3 fn to_string(&self) -> String {4 // ...5 }6}78// Реализация для всех ссылок9impl<T: Summary> Summary for &T {10 fn summarize(&self) -> String {11 (**self).summarize()12 }13}
Default Implementations
1trait Animal {2 fn name(&self) -> &str;3 fn sound(&self) -> &str {4 "No sound"5 }6}78struct Dog {9 name: String,10}1112impl Animal for Dog {13 fn name(&self) -> &str {14 &self.name15 }1617 fn sound(&self) -> &str {18 "Woof!"19 }20}2122struct Fish {23 name: String,24}2526impl Animal for Fish {27 fn name(&self) -> &str {28 &self.name29 }30 // sound() использует значение по умолчанию31}
Static Dispatch vs Dynamic Dispatch
▸Static dispatch (generics)
1// Код дженерика дублируется для каждого типа2fn process_static<T: Summary>(item: T) {3 println!("{}", item.summarize());4}56// Вызов7process_static(article); // Отдельная функция для Article8process_static(tweet); // Отдельная функция для Tweet
▸Dynamic dispatch (trait objects)
1// Одна функция для всех типов2fn process_dynamic(item: &dyn Summary) {3 println!("{}", item.summarize());4}56// Использование7let items: Vec<Box<dyn Summary>> = vec![8 Box::new(article),9 Box::new(tweet),10];1112for item in &items {13 process_dynamic(item.as_ref());14}
▸Сравнение
Derive Macros
1#[derive(Debug, Clone, PartialEq)]2struct User {3 name: String,4 age: u32,5}67// Автоматическая реализация8impl std::fmt::Display for User {9 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {10 write!(f, "User {{ name: {}, age: {} }}", self.name, self.age)11 }12}
Практические примеры
▸Ограничения для функций
1fn find_largest<T>(list: &[T]) -> &T2where3 T: PartialOrd,4{5 let mut largest = &list[0];6 for item in &list[1..] {7 if item > largest {8 largest = item;9 }10 }11 largest12}
▸Паттерн "Newtype"
1struct Meters(f64);2struct Kilometers(f64);34impl Meters {5 fn to_kilometers(&self) -> Kilometers {6 Kilometers(self.0 / 1000.0)7 }8}
Заключение
Traits и generics — мощная система типов Rust, обеспечивающая полиморфизм без потери производительности. Понимание trait bounds, associated types и dispatch критически важно для идиоматичного Rust. На собеседовании спрашивают про разницу static vs dynamic dispatch, как работают lifetime'ы в generics, и типичные паттерны.