如何从方法中修改并返回 self?

问题描述 投票:0回答:2

我有一个结构和各自的实现:

pub struct Departments {
    pub id: String,
    pub linked_accounts: Vec<Account>,
}

impl Departments {
    pub fn add_account(&mut self, acct: Account) -> Self {
        let mut vec: Vec<Account> = self.linked_accounts;
        vec.push(acct);

        Self {
            id: self.id,
            linked_accounts: vec,
        }
    }
}
error[E0507]: cannot move out of `self.linked_accounts` which is behind a mutable reference
  --> src/lib.rs:10:37
   |
10 |         let mut vec: Vec<Account> = self.linked_accounts;
   |                                     ^^^^^^^^^^^^^^^^^^^^ move occurs because `self.linked_accounts` has type `Vec<Account>`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
10 |         let mut vec: Vec<Account> = &self.linked_accounts;
   |                                     +

error[E0507]: cannot move out of `self.id` which is behind a mutable reference
  --> src/lib.rs:14:17
   |
14 |             id: self.id, //*Error here*
   |                 ^^^^^^^ move occurs because `self.id` has type `String`, which does not implement the `Copy` trait

我在从数据库加载部门、添加帐户并将其存储回数据库时使用它:

match db.get::<Departments>(id).await? {
    None => bail!("No records found"),
    Some(departments) => {
        let mut departments = departments;

        departments.add_account(Account::Credit);

        let id = Id::new(Departments::KIND, &id);
        gh.update::<_, Departments>(id, departments.clone()).await?;
    }
}

我该如何解决这个问题?

rust borrow-checker
2个回答
2
投票

有几种方法可以解释您的问题。在所有情况下,答案都以 “您的函数签名是错误的” 开头,但它到底应该是什么,取决于您的用例。

但最肯定的是,它应该是以下之一:

  • pub fn add_account(&mut self, acct: Account)
  • pub fn add_account(&mut self, acct: Account) -> &mut Self
  • pub fn add_account(mut self, acct: Account) -> Self

我认为您最大的误解是您认为您需要返回

Self
。您使用
add_account
的方式,只需在
departments.add_account(Account::Credit)
上调用它就不会
 要求您返回 
Self
。您可以直接修改
self

对象:
pub struct Departments {
    pub id: String,
    pub linked_accounts: Vec<Account>,
}

impl Departments {
    pub fn add_account(&mut self, acct: Account) {
        self.linked_accounts.push(acct);
    }
}

现在,有一个用例,您希望返回某种形式的 
Self

,也就是说,如果您希望能够链接这些调用:
departments
    .add_account(Account::Credit)
    .add_account(Account::Debit)
    .add_account(Account::Savings);

这通常是通过返回 
&mut Self

:
 来完成的
pub struct Departments { pub id: String, pub linked_accounts: Vec<Account>, } impl Departments { pub fn add_account(&mut self, acct: Account) -> &mut Self { self.linked_accounts.push(acct); self } }

请注意,这个 still

 不需要您实例化一个新的 
Self

对象,就像您在代码中所做的那样。

实际错误

如果您想了解原始错误:
  • &mut self
    的说法意味着你只借了
    self
  • ,并且你必须在某个时候归还它。 (在函数结束时自动发生)
  • let mut vec: Vec<Account> = self.linked_accounts; 
    linked_accounts
    成员移出
    self
    。只有当我们拥有
    self
    而不是借用它时,这才有可能,因为这样,我们就可以按照自己的意愿拆除它。但由于我们需要归还它,所以我们不能只是将成员移出。

我没有更详细地讨论实际错误,因为它只是错误函数签名的产物,并没有真正对解决方案做出有意义的贡献。

无论哪种方式,我认为您对所有权如何运作存在一些误解,所以我建议阅读 Rust 书中的所有权章节

我认为您有误解的原因是,如果您的函数签名包含

Self
,则实际上不可能返回
&mut self
Self
是拥有的,如果不复制借用的对象,则无法创建拥有的对象。

是的,您正在尝试创建它的副本以尝试实现它,但您发布的使用示例向我表明您实际上并不想创建副本。


© www.soinside.com 2019 - 2024. All rights reserved.