gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:58:48 25 4
gpt4 key购买 nike

这是一个简化的例子:

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

编译器报告在 12 处有两个可变借用,但事实并非如此。由于 trans.commit() 按值获取 selftrans 被丢弃,所以到点 2 应该有没有可变引用。

  1. 为什么编译器看不到 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
}
}
}

关于rust - 为什么对已删除对象的可变引用仍算作可变引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41732404/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com