【问题标题】:Can an inner Rust struct be passed a reference to its owner? [duplicate]内部 Rust 结构可以传递对其所有者的引用吗? [复制]
【发布时间】:2020-10-20 09:48:02
【问题描述】:

从重复中,一组真正出色的解决此问题的模式是documented by @Shepmaster in this answer。谢谢你????


Account在调用方法时需要访问Bank的字段。 Bankdeposit() 调用set() 的帐户,但set() 需要了解有关银行的一些信息,因此必须将银行传递给Account::set。我确信有其他方法可以解决这个问题,这在 Rust 中更有意义。我很难找到更好的替代模式来代替我用其他语言做的事情。

这是来自 a Twitch stream 的一个最小示例,我尝试在 Rust 中创建一个简单的流行病学模型 - 如果我理解了,我将在下一个中给出答案????。

fn main() {
    // create a bank and fill with accounts:
    let mut bank = Bank { accounts: vec![] };
    for i in 0..100 {
        bank.accounts.push(Account {
            id: i,
            balance: 0,
            mean_deviation: 0,
        });
    }

    // set the balance of an account
    bank.deposit(42, 10000);
}

// BANK:
struct Bank {
    accounts: Vec<Account>,
}

impl Bank {
    pub fn deposit(&mut self, id: usize, balance: i32) {
        let account = self.accounts.get_mut(id).unwrap();

        // this fails, because account needs access to information from the bank struct,
        // and we cannot borrow bank as mutable twice, or immutable when already mutable:
        account.set(balance, self);
    }
}

// ACCOUNT:
struct Account {
    id: i32,
    balance: i32,
    mean_deviation: i32,
}

impl Account {
    pub fn set(&mut self, balance: i32, bank: &Bank) {
        self.balance = balance;

        /* use bank to calculate how far from the mean account value this account is */
    }
}
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/main.rs:27:30
   |
23 |         let account = self.accounts.get_mut(id).unwrap();
   |                       ------------- mutable borrow occurs here
...
27 |         account.set(balance, self);
   |                 ---          ^^^^ immutable borrow occurs here
   |                 |
   |                 mutable borrow later used by call

【问题讨论】:

    标签: rust


    【解决方案1】:

    老实说,最好的方法是尽可能避免它。 circular references are not good at all

    这是另一种思考方式: 通过使用包含帐户余额的Cell,您可以根据需要读取/写入新值。

    use std::cell::Cell;
    fn main() {
        // create a bank and fill with accounts:
        let mut bank = Bank { accounts: vec![] };
        for i in 0..100 {
            bank.accounts.push(Account {
                id: i,
                balance: Cell::new(0),
                mean_deviation: Cell::new(0),
            });
        }
    
        // set the balance of an account
        bank.deposit(42, 10000);
    }
    
    // BANK:
    struct Bank {
        accounts: Vec<Account>,
    }
    
    impl Bank {
        pub fn deposit(&self, id: usize, balance: i32) {
            let account = self.accounts.get(id).unwrap();
            account.set(balance, &self);
        }
    }
    
    // ACCOUNT:
    struct Account {
        id: i32,
        balance: Cell<i32>,
        mean_deviation: Cell<i32>,
    }
    
    impl Account {
        pub fn set(&self, balance: i32, bank: &Bank) {
            let old_balance = self.balance.get();
            self.balance.set(old_balance + balance);
            /* use bank to calculate how far from the mean account value this account is */
            let _ = bank.accounts.len();
        }
    }
    
    

    如果出于某种原因你愿意在多线程中使用它,你应该使用atomic 类型来表示简单的原语。

    【讨论】:

    • 感谢您的回复(:因此,为了处理语言的限制,将所有逻辑移出 Account 并移入 Bank 或可能是管理逻辑的第三个对象更有意义?
    • 我想这不是语言限制,因为没有 GC 可以管理引用,您也可以使用 RcArcRwLock 但这是很多开销这可以通过使用 Cell 来避免(对于您的情况)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多