Dear all,
I am quite new in Rust (coming from python and C++), and I have some issue regarding lifetime.
I tried to implement a very simple program (see bellow) that has same structure that my program. Any help on how I must implement lifetime in this example will be very welcome (and if possible with explaination, so I will be able to understand, and not request help anymore )
Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
--> src/main.rs:31:15
|
31 | r.s = Some(self.m);
| ^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'c as defined on the impl at 29:6...
--> src/main.rs:29:6
|
29 | impl<'c> Trait2<'c> for Data<'c> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:31:20
|
31 | r.s = Some(self.m);
| ^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the method body at 30:5...
--> src/main.rs:30:5
|
30 | / fn function_2(&self, r: &'c mut Rec) -> bool {
31 | | r.s = Some(self.m);
32 | | true
33 | | }
| |_____^
= note: ...so that the expression is assignable:
expected std::option::Option<&std::boxed::Box<(dyn Trait1 + 'static)>>
found std::option::Option<&std::boxed::Box<dyn Trait1>>
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
error: Could not compile `playground`.
To learn more, run the command again with --verbose.
Is there some reason you're doing double-indirection on your trait objects? Why are you storing &'a Box<dyn Trait1> rather than &'a dyn Trait1? Also, be aware that boxed trait objects by default are constrained by the 'static lifetime, so you might be wanting to use Box<Trait1 + 'a> instead to loosen that constraint. But I don't know how to reconcile that with the lifetime of the borrow you're storing, which is why I asked the first question. It looks wonky to me, but I haven't looked that closely.
Specifically, I think the problem you're having is that the &'b Box<Trait1> in Data requires the boxed object to have a 'static lifetime, but you're allocating it within main, and it only lives as long as the Struct1 that owns it. Try making Data generic over the lifetime of the trait object by storing something like &'b Box<Trait1 + 'c>.
Box is a pointer, so &Box is equivalent of C++'s Trait**, except & also locks it to be read-only.
References are locks that make structs containing them locked to a temporary scope. They don't act like pointers. As a guideline, use only owned types in structs, and only references in function args. Other cases are relatively rare, and require more practice with ownership semantics.
When beginning with Rust notions, follow @kornel advice.
Now, regarding your piece of code, instead of &'a Rec (i.e., &'a Rec<'_>) you want &'_ Rec<'a>.
Add #![deny(elided_lifetimes_in_paths)], it will help you see where you forgot to annotate structs lifetime parameters (non-annotated lifetime parameters in method arguments let Rust use independent lifetime parameters instead of the ones required).
I also recommend using #![deny(bare_trait_objects)] to help distinguish between types and traits:
I miss the fact Box is already a pointer, so I will have to change that.
I will try to follow your advices, and I will have a deeper look at your code sample.