I apologize if my question seems trivial as I am new to this platform and the Rust language.
I've got the "cannot borrow self.reservations as mutable because it is also borrowed as immutable" error when trying to implement a simple project.
error[E0502]: cannot borrow `self.reservations` as mutable because it is also borrowed as immutable
--> src/repository.rs:48:9
|
16 | impl<'a> LicenseRepository<'a> {
| -- lifetime `'a` defined here
...
44 | let plan = self.find_plan_by_code(plan_code)?;
| ---------------------------------
| |
| immutable borrow occurs here
| argument requires that `*self` is borrowed for `'a`
...
48 | self.reservations.push(reservation);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
I've manipulated the code a lot to fix it, but it's not working as I expected, so I decided to ask some experts here about this issue. By the way, why 'a is necessary in the &'a mut self parameter of add_reservation method? If I omit it, it gives me an error saying "lifetime may not live long enough" for that same line (let plan = self.find_plan_by_code(plan_code)?;).
By writing &'a mut self, you've created a borrow of type &'a mut LicenseRepository<'a>, which says that self must be borrowed for as long as 'a, the lifetime that's also used in the struct type. You don't want that, because it means the struct is exclusively borrowed for the rest of its own existence, which is a mostly useless thing. Don't ever write that. If you find yourself seeming to need it, you have a problem earlier.
In this case, the problem is that you're trying to have a LicenseRepository store references to other data that is owned by the same struct. That will always give you problems; don't do that. In general, don't store references in your application's data structures; to a first approximation, references are meant only for temporary uses.
If you are concerned about duplication, you can use Rc or Arc to share data instead of referencing or cloning it. Or, it may be better to store some ID/key value to use in lookups instead.
The compiler probably incorrectly pointed you in this direction (telling you to add 'a to &mut self) because you're trying to create a self-referential struct by storing a borrow you get from find_plan_by_code into self.reservations.
The correct high-level advice is "don't create self-referential structs". Probably you are overusing references/lifetimes. Store owned objects instead. Rust types with lifetimes are generally for short-lived borrows, not long-term storage.
the Plan actually contains a list of features that are stored as owned separately, so I reference to them in Plan. LicenseReservation contains a reference to Plans.
Is this a good approach to have all this information together in one struct?
That is exactly what you must not do. This is not a feasible use of references. Forget references exist, and design a data structure that does not use them.
Thank you for your helpful answer. You are correct. The compiler suggested that I add that 'a to the &'a mut self parameter. Could you please take a look at my response to @kpreid answer here and give me a suggestion about structure here?
Replace &'a Feature and the like with Rc<Feature> or Arc<Feature>.
Or perhaps have features: HashMap<FeatureId, Feature> and replace &'a Feature with FeatureId.
There are many approaches, but the key idea is that if you have different parts of your data structure "pointing" at each other, don't use references to do the "pointing".[1] Instead use shared ownership pointers like Rc/Arc, use indices or other identifiers, etc.
&_ or &mut _ or really, anything with a lifetime âŠī¸
Thank you for bringing up the main issue. You are absolutely right I mistakenly approached this situation with the mindset of other programming languages.