Как инициализировать две переменные в операторе сопоставления, не вызывая раздражения средства проверки заимствований?

Итак, у меня есть код, который использует 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

Я действительно много чего перепробовал и стараюсь бешено гуглить. Но я застрял.

Есть ли вообще способ сделать это, который не был бы совершенно уродливым и идиоматическим? Мне кажется, что это действительно глупая проблема, и я упускаю здесь что-то фундаментальное… 

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что попытка «вернуть» и 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 можно выполнить «отложенную инициализацию». Это очень элегантно.

Aymeric Barthe 26.04.2024 14:12

Другие вопросы по теме