Searching with traits
- Rust course
- Intermediate
- Lesson 28/115
- 6 min
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.
Practice 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.
Starter code
fn main() {
// buraya yaz
}Sample 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(", "));
}Expected output
2: Tutunamayanlar, Tehlikeli Oyunlar
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 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 Correct answer
- &T prints faster
- Vec<T> can't be generic
- No difference
Explanation: Items can't be moved out of a shelf borrowed with &self; returning references is also cheaper than copying.
2 Bounded search
impl<T: ____> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
impl<T: Aranabilir> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
Explanation: ara exists only on shelves holding Aranabilir items.
3 Query and matching books
| Term | Meaning |
|---|---|
"atay" |
Tutunamayanlar, Tehlikeli Oyunlar |
"MADONNA" |
Kürk Mantolu Madonna |
"sabahattin" |
Only Ali's book |
"xyz" |
Empty vector |