【问题标题】:why is rust 'pub fn func(&'a mut self)' considered "mutably borrowed" after run?为什么 rust 'pub fn func(&'a mut self)' 在运行后被认为是“可变借用”?
【发布时间】:2021-09-03 07:26:35
【问题描述】:

tl;dr 给定pub fn func(&'a mut self),为什么selffunc 运行后被认为是“可变借用”

鉴于以下最小可行示例 (playground)

pub struct Struct1<'a> {
    var: &'a u8,
}

impl<'a> Struct1<'a> {
    pub fn new() -> Struct1<'a> {
        return Struct1 {
            var: &33,
        }
    }
    pub fn func(&'a mut self) -> () {
        ()
    }
}

fn main() {
    let mut s1 = Struct1::new();
    s1.func();  // point 1
                // point 2
    s1.func();  // point 3
}

导致编译器错误

error[E0499]: cannot borrow `s1` as mutable more than once at a time
  --> src/test12-borrow-mut-struct-twice-okay.rs:20:5
   |
18 |     s1.func();  // point 1
   |     -- first mutable borrow occurs here
19 |                 // point 2
20 |     s1.func();  // point 3
   |     ^^
   |     |
   |     second mutable borrow occurs here
   |     first borrow later used here

然而,// point 2 s1 在我看来不再被借用了。 func 已完成运行。 func 内还有什么可以借用 self!?看来func //point 1 已放弃对s1 的控制。

s1// point 3 还借用什么?


类似问题:

【问题讨论】:

  • 我知道有类似的问题。大多数这些问题都集中在解决特定问题上。然而,我希望一些防锈专家能够果断地回答更广泛的问题。
  • 它仍然是借用的,因为 you 告诉编译器您正在借用 'a 生命周期,该生命周期定义在 impl 块上,即 'a 生命周期与结构有关。您的 &amp;'a mut self 脱糖到 self: &amp;'a mut Struct&lt;'a&gt;
  • @DenysSéguret 好的,我会充实答案。
  • 感谢@DenysSéguret。事实上,这个问题潜伏在许多 SO rust 问题中。然而,他们中的大多数人在试图解决其他问题时以一种复杂的方式触及它。我想把它提炼成最简单的形式,并专注于潜在的 rust 概念,这样我就可以理解如何解决它的所有形式,而不是仅仅复制+粘贴某人的代码建议。
  • @DenysSéguret this one 似乎是一个更直接的复制品,但反过来问这个问题很难找到。当然,“第二个可变借用发生在这里”与数百万个与函数原型错误无关的问题相匹配。

标签: rust


【解决方案1】:

在第 3 点仍然借用 s1 的是什么?

你告诉编译器它仍然是借用的,所以它信任你:虽然编译器会验证你的生命周期不会太短,但它并不关心它们是否太长以至于无法使用。

当您编写&amp;'a mut self 时,'a 是在impl 块上声明的那个,因此也是在结构上定义的那个。 &amp;'a mut selfliterally desugars to:

self: &'a mut Struct1<'a>

所以一旦你调用了func(),rust 编译器就会运行“好吧,这是为'a 借用的,这是与s1 相关联的生命周期'static,所以这是可变地永远借用,美好的一天” ,因此你会被“锁定”在结构之外。

实际上,您可以通过尝试在 func 上显式声明 'a 来查看此别名:

    pub fn func<'a>(&'a mut self) -> () {
        ()
    }
error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
  --> src/main.rs:11:17
   |
5  | impl<'a> Struct1<'a> {
   |      -- first declared here
...
11 |     pub fn func<'a>(&'a mut self) -> () {
   |                 ^^ lifetime `'a` already in scope

error: aborting due to previous error

Rust 毫不含糊地告诉你,在块内 'a 总是指在 impl 块上声明的生命周期。

解决方案是删除'a,这完全是错误的生命周期:

    pub fn func(&mut self) -> () {
        ()
    }

在这种情况下,rustc 会自动引入生命周期,因为函数实际上并没有借用任何东西,所以生命周期只会扩展到函数调用。

【讨论】:

  • 啊!事实上,我的实际程序,而不是这里的示例,是在我删除 struct 函数上不必要的生命周期时编译的。极好的!现在您指出这一点非常明显。我是个 rust n00b,我认为我更好地理解了生命周期(尽管我一直告诉自己“我想我现在理解 rust”然后我没有 ? )。非常感谢!
  • s1关联的生命周期不是'static;它是一个生命周期 'a 尚未由编译器确定,但这至少涵盖了 s1 超出范围之前的时间。这仍然意味着对func() 的任何调用都会借用s1,只要它存在,因此它不会改变您给出的推理。
猜你喜欢
  • 2014-11-29
  • 1970-01-01
  • 2017-08-10
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多