Существует изменчивая ссылка.
Если изменить transaction
к этому:
fn transaction(&mut self) -> Transaction {
let _:() = self;
Transaction{conn: self}
}
Вы увидите, что ошибки компилятора с:
= note: expected type `()`
= note: found type `&mut Connection`
Так self
имеет типа &mut Connection
... изменяемую ссылка. Затем вы передаете это в экземпляр Transaction
, который возвращается из этой функции.
Это означает, что ваш изменяемый заем существует в течение всей жизни trans
(фигурные скобки добавленные мной, чтобы показать масштабы заема):
let mut trans = db_conn.transaction();
{ // <-------------------- Borrow starts here
let mut records_without_sync = 0_usize;
const MAX_RECORDS_WITHOUT_SYNC: usize = 100;
loop {
//do something
records_without_sync += 1;
if records_without_sync >= MAX_RECORDS_WITHOUT_SYNC {
trans.commit();
records_without_sync = 0;
trans = db_conn.transaction();// <--- ####### D'oh! Still mutably borrowed
}
}
} // <-------------------- Borrow ends here
Если вы ищете такого рода parent-><-child
установки, я подумайте, что вам нужно будет достичь Rc<RefCell>
.
В частности, Rc
, чтобы указать количество, сколько раз вы проходите соединение и RefCell
, чтобы отслеживать заимствования во время выполнения, а не время компиляции. Да, это означает, что вы будете паниковать, если вам удастся попытаться и позаимствовать его дважды во время выполнения. Не зная больше о вашей архитектуре, трудно сказать, подходит ли это или нет.
Here is my solution anyway:
use std::cell::RefCell;
use std::rc::Rc;
struct Connection {}
impl Connection {
fn do_something_mutable(&mut self) {
println!("Did something mutable");
}
}
type Conn = Rc<RefCell<Connection>>;
struct Transaction {
conn: Conn,
}
impl Transaction {
fn new(connection: Conn) -> Transaction {
Transaction { conn: connection }
}
fn commit(mut self) {
self.conn.borrow_mut().do_something_mutable();
}
}
fn main() {
let db_conn = Rc::new(RefCell::new(Connection {}));
let mut trans = Transaction::new(db_conn.clone());
let mut records_without_sync = 0_usize;
const MAX_RECORDS_WITHOUT_SYNC: usize = 100;
loop {
//do something
records_without_sync += 1;
if records_without_sync >= MAX_RECORDS_WITHOUT_SYNC {
trans.commit();
records_without_sync = 0;
trans = Transaction::new(db_conn.clone());
break; // Used to stop the loop crashing the playground
}
}
}
В конце концов, [ваш код просто должен работать] (https://internals.rust-lang.org/t/non-lexical-lifetimes-based-on-liveness/3428) , но Руста еще нет. –