Rust
Трейты и обобщённые функции
Свой трейт, реализация по умолчанию, дженерики с ограничениями и динамическая диспетчеризация.
Код
use std::fmt::Display;
trait Shape {
fn area(&self) -> f64;
fn name(&self) -> &str;
// Реализация по умолчанию — можно не переопределять
fn describe(&self) -> String {
format!("{}: площадь {:.2}", self.name(), self.area())
}
}
struct Circle { radius: f64 }
struct Rect { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { std::f64::consts::PI * self.radius.powi(2) }
fn name(&self) -> &str { "Круг" }
}
impl Shape for Rect {
fn area(&self) -> f64 { self.width * self.height }
fn name(&self) -> &str { "Прямоугольник" }
}
// Статическая диспетчеризация: своя копия функции для каждого типа
fn print_area<T: Shape>(shape: &T) {
println!("{}", shape.describe());
}
// Динамическая: разные типы в одной коллекции
fn total_area(shapes: &[Box<dyn Shape>]) -> f64 {
shapes.iter().map(|s| s.area()).sum()
}
// Несколько ограничений через where
fn largest<T>(items: &[T]) -> Option<&T>
where
T: PartialOrd + Display,
{
items.iter().fold(None, |max, item| match max {
Some(m) if m >= item => Some(m),
_ => Some(item),
})
}
fn main() {
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 2.0 }),
Box::new(Rect { width: 3.0, height: 4.0 }),
];
shapes.iter().for_each(|s| println!("{}", s.describe()));
println!("Суммарная площадь: {:.2}", total_area(&shapes));
println!("{:?}", largest(&[3, 7, 2, 9, 4]));
}