Reputation:
I'm trying to get this filter to work, my other tests pass but the find_by
function isn't compiling. I'm getting an error no field name on type T
. What am I missing here in regards to the filter accessing the fields? I made a version of this code without generics and it works correctly.
Here is my code:
pub struct Repository<T> {
store: Vec<T>
}
impl<T> Repository<T> {
pub fn create() -> Repository<T> {
Repository::<T> {
store: vec![]
}
}
pub fn find_all(self) -> Vec<T> {
self.store
}
pub fn add(&mut self, item: T) {
&mut self.store.push(item);
}
// this method returns an error
pub fn find_by(self, name: &str) -> Vec<T> {
self.store.into_iter().filter(|&e| e.name == name).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
// ...
#[test]
fn can_find_objects_in_repository_by_param() {
#[derive(Debug, PartialEq)]
pub struct Cat { pub name: String };
impl Cat {
pub fn create(name: &str) -> Cat { Cat { name: name.to_string() } }
}
let mut repo = Repository::<Cat>::create();
let c1 = Cat::create("Mittens");
let c2 = Cat::create("Tiger");
repo.add(c1);
repo.add(c2);
assert_eq!(repo.find_by("Tiger"), vec![Cat { name: "Tiger".to_string() }]);
}
}
If I remove the filter the code compiles and the test fails with the following error as expected:
left: `[Cat { name: "Mittens" }, Cat { name: "Tiger" }]`,
right: `[Cat { name: "Tiger" }]`'
Upvotes: 0
Views: 527
Reputation: 983
It works if you define a trait Named
your Cat
will implement. This trait contains the name()
method, thus solving your problem.
Here is the main changes to apply:
// …
pub trait Named {
fn name(&self) -> &str;
}
impl<T> Repository<T> where T: Named {
// …
// this method returns an error
pub fn find_by(self, name: &str) -> Vec<T> {
self.store.into_iter().filter(|e| e.name() == name).collect()
}
// …
#[cfg(test)]
mod tests {
// …
impl Named for Cat {
fn name(&self) -> &str {
&self.name
}
}
See the whole code on rust playground.
Upvotes: 1