I say "perpetual" because I am in the midst of my second or third attempt to learn Rust: the first time was in 2015, then I started again about 2 years ago, then ... mostly gave up for a while, then got back into it this summer.
Anyway, I keep running into the same or very similar issues: things seem to go well, and I seem to understand what I am doing, as long as I am working with practice material (I've been through part of the canonical Book; currently working with the Blandy & Orendorff book; did the Rustlings course last week, etc). But the moment I start trying to develop something practical (which is how I learn best), I immediately run into seemingly insoluble issues with ownership/lifetimes/borrowing, and when that happens, everything I do to try to solve the problem just makes it worse. Which is the whole reason I gave up before.
Anyway, right now I'm trying to create a smallish library (with command-line tool) that stores data in a SQLite database - for which I am using the rusqlite crate. It's not a database client per se - just happens to store data in a database, so none of the DB interaction will be exposed to the user. Here's what my code looks like right now:
use rusqlite::{params, Connection, Result};
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct Database<'a> {
path: &'a Path,
conn: Option<Connection>,
}
impl<'a> Database<'a> {
pub fn new(path: &'a Path, overwrite: bool) -> Result<Self, Box<dyn std::error::Error>> {
if &path.exists() & !overwrite {
panic!("DB file '{:?}' already exists.", &path);
}
let konn = Connection::open(&path)?;
Ok(Database { path: &path, conn: Some(konn) })
}
pub fn open(&mut self) {
if let Ok(konn) = Connection::open(self.path) {
self.conn = Some(konn);
}
}
pub fn close(&mut self) {
if let Some(konn) = &self.conn {
if let Ok(_) = konn.close() { // NOPE!
self.conn = None
}
}
}
}
The rationale for wrapping the rusqlite::Connection in my own Database object is that I expect the application to repeatedly access a single DB file, and I want it to automatically open and close the connection as needed.
As indicated by the "NOPE!" comment, compilation fails where I try to close the DB connection, because konn.close() requires a move, which is not permitted. And that totally makes sense, but I don't have the faintest idea of what to do about it. I'm prepared to believe that I'm thinking about the problem in the wrong way, but if so, I have no idea of the right way.
Solutions for this specific situation would of course be helpful, but I think what would be even more helpful is higher-level advice on how to conceptualize this kind of issue - because as I mentioned above, this kind of thing keeps happening, and it's driving me crazy! ![]()