Completing a counter check when using characteristics as a type parameter

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?

+5
source share
1 answer

The problem is that the borrow verification tool causes the &mut Trait link lifetime to be the same as the whole GenericStruct . I believe this is because the link is a type parameter of the structure itself.

Since your structure does not have fields in which the link is stored (if you need to do this in the source code, please update your question), then you can transfer the type parameter directly to the method, and not to the structure:

 trait Trait{} struct FooBar; impl Trait for FooBar{} struct GenericStruct; impl GenericStruct { fn bar<T>(&self, _: T) {} } fn main() { let mut foobar = FooBar; { let foo = GenericStruct; foo.bar(&mut foobar); foo.bar(&mut foobar); } } 

This will cause the loan to continue until foo.bar() called.

+3
source

Source: https://habr.com/ru/post/1211035/


All Articles