I'm relatively new to Rust. I have written the code below.
The idea is that a new Client is "uninitialized" (log_in() hasn't been called), but certain methods (get_data() in this example) lazily do that before they call any other Connection methods. There is also some data foo that is stored in the Client and is needed by get_data().
See, all the methods of Client basically call connection() to lazily initialize the Client and then call various methods of Connection with various parameters from Client. If I have to copy each of those parameters before I can use them, it feels like there must be a better structure.
I'm doing this lazy initialization because making a network request in new() feels just wrong.
Maybe I should have a login() method and force users of Client to call it before each method call? But that feels like redundant code for something that Client could do on its own.
Not a requirement, I just thought it makes it more convenient. I considered renaming it to init() and removing the return value, but then the methods of Client would look like this
What about calling your constructor something like connect() instead? Nothing mandates the name new(), and it doesn’t feel right to me for the object to not be ready for use when the constructor returns.
If you do decide to keep the lazy initialization, consider using interior mutability to store the connection (like inside a RefCell or RwLock) so that you don’t need every method to take &mut self.
Move the abstraction to the type / field that involves it: you are lazily initializing a Connection, so it looks like you should have a LazyConnection wrapper around Connection that does that, but then only interacting with the .connection field specifically, thus letting Rust see that .foo is indeed not borrowed:
@drewkett I don't think the solutions to this kind of general pattern-related problems are that unique, so any kind of solution would be welcome
Even if yours were to be similar to the one I posted, that would still lead to two slightly different things to achieve the same pattern, which can be useful to better grasp, by comparison, what the pattern really is.