CodeBlanks Logo Icon CodeBlanks

Summary - Trait bounds

Combine trait bounds and where to write a generic max function.

Trait bounds summary

A trait bound defines a generic type's behaviour: <T: Display>, several bounds with +, long bounds with where. impl Trait in a parameter is shorthand for a generic; in return position it means a single hidden type. dyn Trait is runtime dispatch; it holds different types in the same collection and is used behind a pointer. The default choice is generics; use dyn when you need a mixed collection or a plugin structure.

Finding the largest area

Iterator methods can be used on trait objects too. Since f64 isn't Ord, the largest is found with fold instead of max:

fn en_buyuk_alan(v: &[Box<dyn Sekil>]) -> f64 {
    v.iter().map(|s| s.alan()).fold(0.0, f64::max)
}

f64::max, a function taking two arguments, can be passed directly to fold.

Practice Largest area

With the Sekil, Kare and Daire definitions from the previous lesson, write fn en_buyuk_alan(v: &[Box<dyn Sekil>]) -> f64. Print the result with {:.2} for a list containing Kare(2.0), Kare(3.0) and Daire(1.0).

Starter code

main.rs
trait Sekil {
    fn alan(&self) -> f64;
    fn ad(&self) -> String;
}

struct Kare(f64);
struct Daire(f64);

impl Sekil for Kare {
    fn alan(&self) -> f64 {
        self.0 * self.0
    }
    fn ad(&self) -> String {
        String::from("kare")
    }
}

impl Sekil for Daire {
    fn alan(&self) -> f64 {
        std::f64::consts::PI * self.0 * self.0
    }
    fn ad(&self) -> String {
        String::from("daire")
    }
}

fn main() {
    // buraya yaz
}

Sample solution

main.rs
trait Sekil {
    fn alan(&self) -> f64;
    fn ad(&self) -> String;
}

struct Kare(f64);
struct Daire(f64);

impl Sekil for Kare {
    fn alan(&self) -> f64 {
        self.0 * self.0
    }
    fn ad(&self) -> String {
        String::from("kare")
    }
}

impl Sekil for Daire {
    fn alan(&self) -> f64 {
        std::f64::consts::PI * self.0 * self.0
    }
    fn ad(&self) -> String {
        String::from("daire")
    }
}

fn en_buyuk_alan(v: &[Box<dyn Sekil>]) -> f64 {
    v.iter().map(|s| s.alan()).fold(0.0, f64::max)
}

fn main() {
    let v: Vec<Box<dyn Sekil>> = vec![Box::new(Kare(2.0)), Box::new(Kare(3.0)), Box::new(Daire(1.0))];
    println!("{:.2}", en_buyuk_alan(&v));
}

Expected output

9.00

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 How is a <code>Vec&lt;Box&lt;dyn Sekil&gt;&gt;</code> passed to a function taking <code>&amp;[Box&lt;dyn Sekil&gt;]</code>?

  • With &v Correct answer
  • With v
  • v.into()
  • It can't be

Explanation: &Vec<T> converts to &[T] automatically (deref coercion).

2 Largest by folding

Question
v.iter().map(|s| s.alan()).____(0.0, f64::max)
Answer
v.iter().map(|s| s.alan()).fold(0.0, f64::max)

Explanation: fold combines each element starting from an initial value; with f64::max it finds the largest.

3 Group summary

Term Meaning
<T: A + B> Multiple bounds
where Readable bounds
-> impl Trait Single hidden type
Box<dyn Trait> Dynamic dispatch

All lessons in Intermediate