CodeBlanks Logo Icon CodeBlanks

Generic structure

Make the book model generic.

Generic structure

Let's write a Raf (shelf) to hold the books. Making the shelf generic lets the same code be used later for magazines or films:

pub struct Raf<T> {
    ogeler: Vec<T>,
}

impl<T> Raf<T> {
    pub fn new() -> Self { Self { ogeler: Vec::new() } }
    pub fn ekle(&mut self, x: T) { self.ogeler.push(x); }
    pub fn len(&self) -> usize { self.ogeler.len() }
}

Since the Vec stays private, changing the shelf's internals later (e.g. to a BTreeMap) doesn't affect users.

Implementing Default

For types offering an argument-less new, implementing Default is also a convention; then Raf::default() and ..Default::default() work:

impl<T> Default for Raf<T> {
    fn default() -> Self {
        Self::new()
    }
}

let mut sayilar: Raf<u32> = Raf::default();
sayilar.ekle(7);

Thanks to type inference, Raf::new() is usually used without writing the type: the first ekle call determines T.

Practice Two shelves

Inside mod kitaplik, together with the previous Kitap, write a generic Raf<T> (new, ekle, len). Add two books to a book shelf and three numbers to a u32 shelf; print the lengths of both shelves separated by a space.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
mod kitaplik {
    pub struct Kitap {
        ad: String,
        yazar: String,
        yil: u16,
    }

    impl Kitap {
        pub fn new(ad: &str, yazar: &str, yil: u16) -> Self {
            Self {
                ad: ad.to_string(),
                yazar: yazar.to_string(),
                yil,
            }
        }
        pub fn ad(&self) -> &str {
            &self.ad
        }
        pub fn yil(&self) -> u16 {
            self.yil
        }
    }

    pub struct Raf<T> {
        ogeler: Vec<T>,
    }

    impl<T> Raf<T> {
        pub fn new() -> Self {
            Self { ogeler: Vec::new() }
        }
        pub fn ekle(&mut self, x: T) {
            self.ogeler.push(x);
        }
        pub fn len(&self) -> usize {
            self.ogeler.len()
        }
    }
}

use kitaplik::{Kitap, Raf};

fn main() {
    let mut kitaplar = Raf::new();
    kitaplar.ekle(Kitap::new("Tutunamayanlar", "Oğuz Atay", 1972));
    kitaplar.ekle(Kitap::new("Kürk Mantolu Madonna", "Sabahattin Ali", 1943));
    let mut sayilar: Raf<u32> = Raf::new();
    for n in [1, 2, 3] {
        sayilar.ekle(n);
    }
    println!("{} {}", kitaplar.len(), sayilar.len());
}

Expected output

2 3

Questions and answers

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

1 What does Clippy suggest for a type with <code>pub fn len</code>?

  • Nothing
  • Adding pub fn is_empty too Correct answer
  • Removing len
  • Renaming len to size

Explanation: The len_without_is_empty lint: is_empty is an expected API on collection-like types.

2 Generic impl

Question
impl____ Raf<T> {
    pub fn ekle(&mut self, x: T) {
        self.ogeler.push(x);
    }
}
Answer
impl<T> Raf<T> {
    pub fn ekle(&mut self, x: T) {
        self.ogeler.push(x);
    }
}

Explanation: Methods valid for every T go in an impl<T> block.

3 Expression and T

Term Meaning
Raf<Kitap> Book shelf
Raf<u32> Number shelf
Raf::new() + ekle("a") Raf<&str>
Raf::<f64>::default() Empty f64 shelf

All lessons in Intermediate