Rust
Searching with traits
Add search with a Searchable trait.
Searching with a trait
For the shelf to search, its items must be able to say whether they match a query. We express this with a trait and offer the search method only for items implementing it:
pub trait Aranabilir {
fn eslesir(&self, sorgu: &str) -> bool;
}
impl<T: Aranabilir> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
Raf<u32> is still valid but has no ara method, because u32 isn't Aranabilir.
Implementation for Kitap
Let a book match if the query appears in its title or author. Both sides are lowercased to ignore case differences:
impl Aranabilir for Kitap {
fn eslesir(&self, sorgu: &str) -> bool {
let s = sorgu.to_lowercase();
self.ad.to_lowercase().contains(&s)
|| self.yazar.to_lowercase().contains(&s)
}
}
Since the trait is in the same module, it can access Kitap's private fields.
Exercise Search the shelf
With the previous Kitap and Raf, write the Aranabilir trait and the ara method. Add Tutunamayanlar (Oğuz Atay, 1972), Tehlikeli Oyunlar (Oğuz Atay, 1973) and Kürk Mantolu Madonna (Sabahattin Ali, 1943) to the shelf. Print the result of ara("atay") as 2: Tutunamayanlar, Tehlikeli Oyunlar.
Show example solution
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()
}
}
pub trait Aranabilir {
fn eslesir(&self, sorgu: &str) -> bool;
}
impl Aranabilir for Kitap {
fn eslesir(&self, sorgu: &str) -> bool {
let s = sorgu.to_lowercase();
self.ad.to_lowercase().contains(&s) || self.yazar.to_lowercase().contains(&s)
}
}
impl<T: Aranabilir> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
}
use kitaplik::{Kitap, Raf};
fn main() {
let mut raf = Raf::new();
raf.ekle(Kitap::new("Tutunamayanlar", "Oğuz Atay", 1972));
raf.ekle(Kitap::new("Tehlikeli Oyunlar", "Oğuz Atay", 1973));
raf.ekle(Kitap::new("Kürk Mantolu Madonna", "Sabahattin Ali", 1943));
let bulunan = raf.ara("atay");
let adlar: Vec<&str> = bulunan.iter().map(|k| k.ad()).collect();
println!("{}: {}", bulunan.len(), adlar.join(", "));
}
Test yourself
-
Why does <code>ara</code> return <code>Vec<&T></code> rather than <code>Vec<T></code>?
- To show the items without moving them off the shelf or copying them
- &T prints faster
- Vec<T> can't be generic
- No difference
Show answer
To show the items without moving them off the shelf or copying them — Items can't be moved out of a shelf borrowed with &self; returning references is also cheaper than copying.
-
Bounded search
impl<T: ____> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
Show answer
impl<T: Aranabilir> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
-
Query and matching books
- "atay"
- Tutunamayanlar, Tehlikeli Oyunlar
- "MADONNA"
- Kürk Mantolu Madonna
- "sabahattin"
- Only Ali's book
- "xyz"
- Empty vector
Next lesson: Test infrastructure