rustborrow-checker

How can I hold ownership of something and call a method on it that moves the object?


I have the following code, which wont compile because the call to "self.client.dispose()" moves the object 'client' due to dispose having this signature: dispose(self). Is there anyway around this? I want to dispose of the client so I can create a new one and assign it back to the self.client field. Client is not Copy or Clone - it's a real PITA bit of third party code that I cannot alter.

// third party crate
struct Client { ... }
impl Client {
   async fn dispose(self) -> Result<..> {...}
}

// My code starts here 

struct MyStruct {
  client: Client
}

impl MyStruct {
  async fn do_something(&mut self) -> Result<...> {
     // stuff
     let thing = self.client.create();
     match thing {
        ...
        Err(error) => {
          // recover here by recreating the client, first disposing it
          self.client.dispose().await?; <--- not possible, client is moved

          self.client = Client::new(); // somehow mutate self with new Client
        }
     }
  } 
}

I've tried making the client field a Cell, RefCell, Arc, Mutex, Box of Client. I think if someone could please very kindly rewrite this for me so it's possible to dispose of the client and create a new one to mutate self.client with, I can then try to learn from it.

Many thanks.


Solution

  • If the value you are replacing with doesn't depend on owning the previous value, just use std::mem::replace (or std::mem::take if it implements Default).

    let prev_client = std::mem::replace(&mut self.client, Client::new());
    
    // You now have the `Client` that was previously in `self` but has been replaced
    // with a different value. You can now do whatever you like with it, prev_client
    // is the owner now.
    prev_client.dispose().await?;