Hello folks! I know the problem I have is quite common among beginners. I also understand why it happens. What I don't get is how I should solve it.
I have the following code (see full example on Github):
let ads_listing: Vec<Ad> = (0..9).into_iter().filter_map(|i| {
// first, a seller needs to create supply
let mut supply = seller.creates_supply(i);
// later, a marketer will pick up this supply and put it on the market
// FIXME: borrowing error
marketer.makes_market(&mut supply)
}).collect();
// further in this scope:
println!("{:?}", ads_listing);
My question is: how do we fix this kind of problem, when we have a variable declared in some inner scope, and we pass it as a reference to be used outside of the inner scope? Should I be looking into the Smart Pointers (for example, the Box type)?
Regarding, Box, the answer is no. Boxing does not change anything when it comes to lifetimes or the borrow checker. In the given code example, I would probably eliminate every lifetime in your code. Replace every &'a str with a String, and either remove or don't use a reference for the fields that contain your own types.
The main idea is to be clear about who owns who. Try to make sure every value has a single owner. References should not be used to get shared ownership.
Rule of the thumb is never use references in structs. struct <'a> means trouble.
References are inherently temporary and always permanently tied to the scopes they borrow from. That makes your structs temporary and scope-limited too, and 99% of the time that's not what you want.
I started going down the road of adding .clone() in the spots the move would occur, but I'm not sure if that the right approach. Also, I did not manage to make my example in test working. Please let me know what are the patterns that help solving the move/partial move problem. Thank you in advance!
I feel I need to shift my mind a lot from the dynamic languages
Your makes_market method takes self as a parameter. That means it'll consume the instance of the Marketer struct it's used on and destroy it when the function ends. As such you can't use it afterwards. You'll want to use &self (to take a reference to it) or &mut self (if you want to mutate it).
You can avoid all the clones if you make structs like ProviderId take a number rather than a string, so that they can be Copy.
You can also avoid cloning Buyer and friends. Insert it into the hashmap (without cloning), then borrow a reference of them from the hashmap and use that to do the transactions.
Thank you, all kind people, for bearing with me here
I spent some time trying to wrap my head around the advice from this topic, and from what I get now, I should always keep a single source of a particular value. Whenever I need to update the value, I use a function that would take &mut reference and make the required changes.
In case I have a dictionary of values, I understand that cloning the ID is the preferred way of accessing the dictionary items from any place in the nested scopes. Thanks to that I don't have to worry about passing lifetime annotations, and I can keep data integrity (due to not cloning dictionary items).
Thank you once again, everyone! I'll post the working example of my code tomorrow, so other beginners (as myself) could see "where it started" vs. "how's it going"