Reputation: 131
I have a trait Foo
and a struct Bar
. Bar
has a Vec
field which holds any reference that implements Foo
.
trait Foo { }
struct Bar<'a> {
handlers: Vec<&'a mut Foo>,
}
I have another struct Stu
which implements Foo
, and has a method add
to add itself to bar
.
struct Stu { }
impl Foo for Stu { }
impl Stu {
fn add(&mut self, bar: &mut Bar) {
bar.handlers.push(&mut self);
}
}
Because there are many kinds of structs that implement Foo
and the actions finished in add
method are varied and I need a struct that holds all of them (which is Bar
here), I wrote the above code. But the compiler complains:
the trait bound
&mut Stu: Foo
is not satisfied
How can I fix this or realize my desired end goal?
Upvotes: 0
Views: 542
Reputation: 300289
Read the error method more carefully:
the trait bound
&mut Stu: Foo
is not satisfied
versus:
impl Foo for Stu { }
You have implemented Foo
for Stu
, not for &mut Stu
.
In Rust, a value, immutable reference and mutable reference are three distinct entities, and you can implement a trait for either of them independently.
The second corner case is that &mut self
is not pattern matching. In regular pattern matching, &mut a: &mut A
means that a
is of type A
, and indeed the other parameters are so treated.
However, confusingly, &mut self
is just syntactic sugar for self: &mut Self
...
So the type of self
here is &mut Stu
, and therefore you should not qualify it further in the push
call.
Therefore, you have to correct your code to:
impl Stu {
fn add(&mut self, bar: &mut Bar) {
bar.handlers.push(self);
}
}
At this point, you will get an error about lifetime constraints: it is not guaranteed here that self
will outlive Bar
. You need to annotate it (use the same lifetime) to make it work:
impl Stu {
fn add<'a>(&'a mut self, bar: &mut Bar<'a>) {
bar.handlers.push(self);
}
}
Note: when annotating lifetimes, it is unnecessary to annotate them all; it's only necessary to insert a name for those that you want to constrain.
Upvotes: 4
Reputation: 737
I've modified your program to include explicit lifetime <'a, 'b>
which leads to successful compilation.
trait Foo { }
struct Bar<'a> {
pub handlers: Vec<&'a mut Foo>,
}
struct Stu;
impl Foo for Stu { }
impl Stu {
fn add<'a,'b> (&'a mut self, bar: &'b mut Bar<'a>) {
bar.handlers.push(self);
}
}
fn main(){
println!("{:?}", "success");
}
Upvotes: 1