Итак, у меня есть код, который использует rusqlite. И это работает нормально.
pub struct Database {
conn: Connection,
}
impl Database {
pub fn get(self: &Self, id: Option<u64>, name: Option<&str>) -> Result<Option<Record>, Error> {
let mut stmt = match name {
Some(_) => { self.conn.prepare_cached(Self::STMT_GET_ID_NAME) },
None => { self.conn.prepare_cached(Self::STMT_GET_ID) }
}?;
let mut rows = match name {
Some(name) => { stmt.query(params![id, name]) },
None => { stmt.query(params![id]) }
}?;
let row = rows.next()?;
if let Some(row) = row {
let record = Record {
id: row.get(0)?,
parent: row.get(1)?,
name: row.get(2)?,
record_type: row.get(3)?,
timestamp: row.get(4)?,
created_at: row.get(5)?,
modified_at: row.get(6)?,
size: row.get(7)?,
hash: row.get(8)?,
inode: row.get(9)?
};
Ok(Some(record))
} else {
Ok(None)
}
}
}
У меня проблема в том, что оператор match по сути дублируется.
Я пробовал что-то подобное, но это не сработает.
let (mut stmt, mut rows) = match name {
Some(name) => {
let mut stmt = self.conn.prepare_cached(Self::STMT_GET_ID_NAME)?;
let rows = stmt.query(params![id, name])?;
(stmt, rows)
}
None => {
let mut stmt = self.conn.prepare_cached(Self::STMT_GET_ID)?;
let rows = stmt.query(params![id])?;
(stmt, rows)
}
};
Проблема в том, что компилятор жалуется на время жизни stmt
error[E0597]: `stmt` does not live long enough
error[E0505]: cannot move out of `stmt` because it is borrowed
Я действительно много чего перепробовал и стараюсь бешено гуглить. Но я застрял.
Есть ли вообще способ сделать это, который не был бы совершенно уродливым и идиоматическим? Мне кажется, что это действительно глупая проблема, и я упускаю здесь что-то фундаментальное…

Проблема в том, что попытка «вернуть» и stmt, и rows из подвыражения перемещает stmt и, следовательно, делает недействительными ссылки, хранящиеся в rows. Чтобы это исправить, вы можете опустить внутренний stmt и назначить его непосредственно внешнему из ваших спичечных рукавов. Таким образом, stmt никогда не перемещается, и программа проверки заимствований счастлива, например. это компилируется:
let mut stmt;
let mut rows = match name {
Some(name) => {
stmt = self.conn.prepare_cached(Self::STMT_GET_ID_NAME)?;
stmt.query(params![id, name])?
}
None => {
stmt = self.conn.prepare_cached(Self::STMT_GET_ID)?;
stmt.query(params![id])?
}
};
Да… это очень хороший момент. Я совсем забыл, что в Rust можно выполнить «отложенную инициализацию». Это очень элегантно.