I'm just learning Rust and I thought I would challenge myself by writing a Telegram RSS bot.
The concept is to fetch the feed, check (with the help of an SQLite database) if the feed contains any new items and then send them to me via the bot.
To check if an item is already in the DB, I count all rows where the id
matches the guid
of the item. I use rusqlite
and I want to prepare a count
statement only once, that I can then reuse for every guid
and for every time I fetch the feed again.
Below is the struct and the constructor for my FeedReader
use rss::Item;
use rusqlite::{Connection, Statement};
use crate::feed::fetch_channel;
pub struct FeedReader<'a> {
url: String,
conn: &'a Connection,
count_stmt: Option<Statement<'a>>,
}
impl<'a> FeedReader<'a> {
pub fn new(url: &str, conn: &'a Connection) -> FeedReader<'a> {
FeedReader {
url: url.to_string(),
conn,
count_stmt: None,
}
}
// ...
}
I implemented a singleton factory method like this:
fn create_count_stmt(&mut self) -> &mut rusqlite::Statement<'a> {
if let Some(stmt) = &mut self.count_stmt {
return stmt;
}
let sql = &"SELECT COUNT(*) FROM guids WHERE id = ?1";
let stmt = self.conn.prepare(sql).unwrap();
self.count_stmt = Some(stmt);
return self.count_stmt.as_mut().unwrap();
}
and I get the following errors:
error[E0506]: cannot assign to `self.count_stmt` because it is borrowed
--> src/feed_reader.rs:51:9
|
43 | fn create_count_stmt(&mut self) -> &mut rusqlite::Statement<'a> {
| - let's call the lifetime of this reference `'1`
44 | if let Some(stmt) = &mut self.count_stmt {
| -------------------- borrow of `self.count_stmt` occurs here
45 | return stmt;
| ---- returning this value requires that `self.count_stmt` is borrowed for `'1`
...
51 | self.count_stmt = Some(stmt);
| ^^^^^^^^^^^^^^^ assignment to borrowed `self.count_stmt` occurs here
error[E0499]: cannot borrow `self.count_stmt` as mutable more than once at a time
--> src/feed_reader.rs:53:16
|
43 | fn create_count_stmt(&mut self) -> &mut rusqlite::Statement<'a> {
| - let's call the lifetime of this reference `'1`
44 | if let Some(stmt) = &mut self.count_stmt {
| -------------------- first mutable borrow occurs here
45 | return stmt;
| ---- returning this value requires that `self.count_stmt` is borrowed for `'1`
...
53 | return self.count_stmt.as_mut().unwrap();
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
I then tried to resolve it and changed it to:
fn create_count_stmt(&mut self) -> &mut rusqlite::Statement<'a> {
if self.count_stmt.is_none() {
let sql = &"SELECT COUNT(*) FROM guids WHERE id = ?1";
let stmt = self.conn.prepare(sql).unwrap();
self.count_stmt = Some(stmt);
}
return self.count_stmt.as_mut().unwrap();
}
This one works but I don't understand what the difference is. As far as I can tell, they both to the same (at least when viewed from the outside).
Can someone please explain this to me?