Rust

Трейты и обобщённые функции

Algonexys · 07.08.2026 · 👁 0

Свой трейт, реализация по умолчанию, дженерики с ограничениями и динамическая диспетчеризация.

Код

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]));
}