I have a problem with checking the borrower when using attributes as a type parameter in the structure:
trait Trait {} struct FooBar; impl Trait for FooBar{} struct Observer<Arg> { action: Box<Fn(Arg) + Send>, // Other fields } impl <Arg> Observer<Arg> { fn new(action: Box<Fn(Arg) + Send>) -> Observer<Arg> { Observer{action: action} } fn execute(&self, arg: Arg) { (*self.action)(arg); } } fn test() { let mut foobar = FooBar; { let mut observer = Observer::new(Box::new(|&: param: &mut Trait| { // do something with param here })); observer.execute(&mut foobar); // First borrow passes ... observer.execute(&mut foobar); // This fails as "foobar" is already borrowed } // The previous borrow ends here (lifetime of "observer") }
Conclusion:
error: cannot borrow `foobar` as mutable more than once at a time observer.execute(&mut foobar); // This fails as "foobar" is already borrowed ^~~~~~ note: previous borrow of `foobar` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foobar` until the borrow ends observer.execute(&mut foobar); // First borrow passes ... ^~~~~~ note: previous borrow ends here { ... } // The previous borrow ends here (lifetime of "observer") ^
However, the following example works:
trait Trait {} struct FooBar; impl Trait for FooBar{} struct Observer { action: Box<Fn(&mut Trait) + Send>, // Other fields } impl Observer { fn new(action: Box<Fn(&mut Trait) + Send>) -> Observer { Observer{action: action} } fn execute(&self, arg: &mut Trait) { (*self.action)(arg); } } fn test() { let mut foobar = FooBar; { let mut observer = Observer::new(Box::new(|&: param: &mut Trait| { // do something with param here })); observer.execute(&mut foobar); observer.execute(&mut foobar); } }
This looks really strange to me, because the second example is just an instance of the first example, and I could (painfully) implement the same thing with macros.
I think this is quite complicated since I need to know the type of parameter accepted by the closure, but I do not need to store this link ...
Is this a mistake in checking a loan? Or am I doing something wrong?
rustc 1.0.0-nightly (44a287e6e 2015-01-08 17:03:40 -0800)
EDIT 1: Exact Usage Example
EDIT 2: As explained in the answer below, the problem is that the borrow verification tool causes the Observer<&mut Type> lifetime to be the same as &mut Type , so the problem is actually not related to the fact that we use the attribute as type parameter (it does the same with the real structure).
Therefore, in my case, I can have a workaround by defining an Observer<Arg> as follows:
struct Observer<Arg> { action: Box<Fn(&mut Arg) + Send>, }
therefore, an argument of type Arg is not in itself a reference, but it makes the code less general. Does anyone have a better solution?