Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rust / rusqlite: cannot move out of a shared reference

I’m keeping a Connection wrapped in an Option in a property of a struct and I’m having trouble closing the Connection. I have checked a lot of answers here at stackoverflow for the general problem but I couldn´t get it working for my case.

Here’s a minimal example to reproduce the error:

use rusqlite::Connection;

struct Db {
    c: Option<Connection>
}

impl Db {

    pub fn new() -> Self {
        return Db { c: None }
    }

    pub fn open(&mut self) {
        self.c = Some(Connection::open("test.db").unwrap());
    }

    pub fn close(&mut self) {
        self.c.as_ref().unwrap().close();
    }

}

fn main() {
    let mut d= Db::new();
    d.open();
    d.close();
}

I get the following output, using Rust 1.61.0 (Arch Linux rust 1:1.61.0-1) with Cargo and rusqlite (rusqlite = { version = "0.27.0", features = ["bundled"] })

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error[E0507]: cannot move out of a shared reference
   --> foo.rs:18:9
    |
18  |         self.c.as_ref().unwrap().close();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^-------
    |         |                        |
    |         |                        value moved due to this method call
    |         move occurs because value has type `Connection`, which does not implement the `Copy` trait
    |
note: this function takes ownership of the receiver `self`, which moves value
   --> ~.cargo/registry/src/github.com-1ecc6299db9ec823/rusqlite-0.27.0/src/lib.rs:725:18
    |
725 |     pub fn close(self) -> Result<(), (Connection, Error)> {
    |                  ^^^^

For more information about this error, try `rustc --explain E0507`.

The function close() from the rusqlite library which the output refers to looks like this:

   /// Close the SQLite connection.
    ///
    /// This is functionally equivalent to the `Drop` implementation for
    /// `Connection` except that on failure, it returns an error and the
    /// connection itself (presumably so closing can be attempted again).
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite call fails.
    #[inline]
    pub fn close(self) -> Result<(), (Connection, Error)> {
        self.flush_prepared_statement_cache();
        let r = self.db.borrow_mut().close();
        r.map_err(move |err| (self, err))
    }

How can I fix this error without changing the general architecture, that is keeping the Connection wrapped in an Option in a property of a struct and closing it via an implementation method?

>Solution :

The Connection::close method consumes self, so you have to take the wrapped value inside self.c out in order to call close on it. After takeing, the c becomes None.

use rusqlite::Connection;

struct Db {
    c: Option<Connection>,
}

impl Db {
    pub fn new() -> Self {
        return Db { c: None };
    }

    pub fn open(&mut self) {
        self.c = Some(Connection::open("test.db").unwrap());
    }

    pub fn close(&mut self) {
        self.c.take().unwrap().close().unwrap();
    }
}

fn main() {
    let mut d = Db::new();
    d.open();
    d.close();
}

Documentation of std::option::Option::take

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading