【问题标题】:Multiple borrows error when fetching and setting a value in Struct在 Struct 中获取和设置值时多次借用错误
【发布时间】:2021-05-02 12:01:09
【问题描述】:

任务

获取和设置struct 中字段值的简单数据结构。

问题

以下get_or_set函数错误与

不能将*self 借用为可变的,因为它也被借用为不可变的

代码

struct MyValue<A> {
    value: Option<A>,
}

impl<A> MyValue<A> {
    fn get(&self) -> &Option<A> {
        &self.value
    }

    fn set<F: FnOnce() -> A>(&mut self, setter: F) -> &Option<A> {
        self.value = Some(setter());
        self.get()
    }

    //this function is causing borrow error
    fn get_or_set<F: FnOnce() -> A>(&mut self, setter: F) -> &Option<A> {
        match self.get() {
            None => self.set(setter),
            some @ Some(_) => some
        }
    }
}

为什么会出现错误?

出现错误后,问题是我在第一个 self.get 超出范围之前第二次调用 self.set 并且不允许多次借用。

修复:

请改用ifelse。这里我给self.get打了两次电话,这不太好。

fn get_or_set<F: FnOnce() -> A>(&mut self, setter: F) -> &Option<A> {
    if self.get().is_some() {
        self.get()
    } else {
        self.set(setter)
    }
}

问题

如何获得借用检查以允许匹配语句也通过?我设置生命周期的尝试没有成功。

fn get_or_set<'a, F: FnOnce() -> A + 'a>(&'a mut self, setter: F) -> &'a Option<A>

【问题讨论】:

标签: rust


【解决方案1】:

你可以这样写你的函数:

fn get_or_set1<F: FnOnce() -> A>(&mut self, setter: F) -> &Option<A> {
    match *self.get() {
        None => self.set(setter),
        _ => &self.value,
    }
}

【讨论】:

  • 成功了!谢谢你。但这太奇怪了。我不明白这背后的原因。错误说我借用了self 两次并指向None 的主体,但第三次使用_ =&gt; &amp;self.value 调用self 修复了它:S
  • match self.get() 创建一个临时变量,该变量引用从get 返回的&amp;Option&lt;T&gt; 作为共享引用,然后当您调用self.set(setter) 时,您尝试再次借用它,这次是可变的。当您取消引用它时,该引用将不再保留。在您的if 中,您不持有引用,因为您调用is_some 方法并获得bool 结果。在此处查看第二段:doc.rust-lang.org/reference/expressions/match-expr.html
  • 问题指出调用self.get() 两次“不好”,但这个答案基本上做同样的事情,除了它通过直接访问self.value 来内联第二个调用(因此破坏封装,如果它是故意的)。
  • @user4815162342 是的,我没有注意到。 -Zpolonius 标志是唯一的解决方案吗?
  • @captain-inquisitive 我不会将-Zpolonius 视为解决方案,因为它在稳定版上不可用。代码与该标志一起工作表明问题不在于您的代码,而在于当前的借用检查器,并且该问题可能会在未来的某个 Rust 版本中消失。但 Polonius 仍处于开发阶段,没有公开时间表说明何时可以投入使用。看看其他类似的问题,似乎调用get() 两次是唯一没有不安全的解决方案。如果您对不安全的解决方案感兴趣,也可以编写一个。
猜你喜欢
  • 1970-01-01
  • 2020-04-25
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
  • 2015-09-13
相关资源
最近更新 更多