rust - 为什么对已删除对象的可变引用仍算作可变引用?

这是一个简化的示例:

struct Connection {}

impl Connection {
    fn transaction(&mut self) -> Transaction {
        Transaction { conn: self }
    }
}

struct Transaction<'conn> {
    conn: &'conn Connection,
}

impl<'conn> Transaction<'conn> {
    fn commit(mut self) {}
}

fn main() {
    let mut db_conn = Connection {};

    let mut trans = db_conn.transaction(); //1
    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(); //2
        }
    }
}

编译器在 1  2 上报告了两个可变借位,但事实并非如此。由于trans.commit()按值接受self,因此会删除trans,因此到 2点点,不应有任何可变引用。
  • 为什么编译器看不到 2 没有可变引用?
  • 我该如何修复代码,而又保持相同的逻辑?

 

最佳答案

有一个可变的引用。

如果将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会在运行时(而不是在编译时)跟踪借入。是的,这的确意味着如果您尝试在运行时两次尝试并可变地借用它,就会感到 panic 。在不了解您的体系结构的情况下,很难说这是否合适。

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
        }
    }
}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

web3.0前沿技术研究者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值