I have a trait MyTrait
which I can implement for Vec<&MyStruct>
. (it only needs reading access, hence the use of references) However, in my code I have a Vec<MyStruct>
. Now I want to use the same implementation. However, it doesn't work. The compiler says it is not implemented for Vec<MyStruct>
. How to fix this?
Knowing what the trait actually does would be helpful, but my guess is that you should implement it for &[MyStruct]
.
Here is my actual code:
struct Filter {
regex: Regex,
want: bool,
description: String,
}
impl Filter {
#[inline]
fn is_ok(&self, hay: &str) -> bool {
self.regex.is_match(hay) == self.want
}
}
trait FilterList {
fn is_ok(&self, hay: &str) -> bool;
}
impl FilterList for Vec<&Filter> {
#[inline]
fn is_ok(&self, hay: &str) -> bool {
self.iter().all(|f| f.is_ok(hay))
}
}
A Filter
is something that takes in a string (called "hay") and then is either ok or not ok. A FilterList
is ok if all of its filters are ok.
I think I should probably implement it for Iterator<Item = &Filter>
, right? I currently figure out how to do this. (it says i need to put dyn
somewhere?! why? and then it says I can't invoke all()
, for whatever reason..) Any help is appreciated..
First, change your trait to take self
by value. You can still implement it for references when needed, but Iterator
requires &mut self
or self
, so &self
would make that impossible. Then you can implement it with a generic.
pub trait FilterList {
fn is_ok(self, hay: &str) -> bool;
}
impl<'a, I> FilterList for I
where
I: Iterator<Item = &'a Filter>,
{
fn is_ok(mut self, hay: &str) -> bool {
self.all(|f| f.is_ok(hay))
}
}
If you want this to work on Vec
, you can instead implement it for IntoIterator
. This will also work for all Iterator
types, since they automatically implement IntoIterator
.
impl<'a, I> FilterList for I
where
I: IntoIterator<Item = &'a Filter>,
{
fn is_ok(self, hay: &str) -> bool {
self.into_iter().all(|f| f.is_ok(hay))
}
}
Implementations like the above in the form impl<T> Trait for T
are blanket impls. You can only make one per trait.
When using this, remember that &Vec<Filter>
implements IntoIterator<Item = &Filter>
, so you can do (&filter_vec).is_ok(hay)
, which is the same as filter_vec.iter().is_ok(hay)
.
I absolutely don't get why I need mut self
and self
instead of &self
and IntoIterator
instead of Iterator
(all of those go in the direction of mutability, though all I do only needs reading access?!), but it works. Thank you very very much!
Obtaining items from an Iterator
mutates the Iterator
You can do this with an owned self
or borrowed &mut self
, but any &mut Iterator
also implements Iterator
, so making it use an owned self means you can use owned or borrowed iterators.
Calling IntoIterator::into_iter
requires ownership.
mut x
and x
are the same function signature. The former is just shorthand for:
fn f(x: T) {
let mut x = x;
}
ok but why can't stay my implementation of Filter::is_ok(...)
with &self
?
You could, but there is no point*. &self
in a trait is nearly always more restrictive than self
. You can implement a trait that takes self
for references, but you can't implement a trait that takes &self
for owned types. These two trait impls are very similar:
pub trait A {
fn a(self);
}
impl<'a> A for &'a String {
fn a(self) {
println!("{}", &self);
}
}
pub trait B {
fn b(&self);
}
impl B for String {
fn b(&self) {
println!("{}", self);
}
}
Both A::a
and B::b
take &String
. But the trait A
is more flexible.
If you use &self
, you can still sort of implement it for Iterator
.
impl<'b, I> FilterList for I
where
for<'a> &'a I: Iterator<Item = &'b Filter>,
{
fn is_ok(&self, hay: &str) -> bool {
let mut this = self;
this.all(|f| f.is_ok(hay))
}
}
This compiles, but it is extremely rare (maybe impossible?) that a type will fulfill the requirements.
It is also possible to implement it for IntoIterator
, and this one is more useful.
impl<I> FilterList for I
where
for<'a> &'a I: IntoIterator<Item = &'a Filter>,
{
fn is_ok(&self, hay: &str) -> bool {
self.into_iter().all(|f| f.is_ok(hay))
}
}
There's many implementations of IntoIterator
for references, like slices &[T]
. However, this is still more restrictive than taking self
by value.
* Traits that are used as trait objects need to take a reference to self, but &self
has the issues above, and &mut self
still has the issue with IntoIterator
.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.