【问题标题】:Where does the problematic borrow happen?有问题的借用发生在哪里?
【发布时间】:2018-12-14 10:49:52
【问题描述】:
pub struct Dest<'a> {
    pub data: Option<&'a i32>,
}

pub struct Src<'a> {
    pub data: Option<&'a i32>,
}

pub trait Flowable<'a: 'b, 'b> {
    fn flow(&'a self, dest: &mut Dest<'b>);
}

impl<'a: 'b, 'b> Flowable<'a, 'b> for Src<'a> {
    fn flow(&self, dest: &mut Dest<'b>) {
        dest.data = self.data;
    }
}

struct ContTrait<'a, 'b> {
    pub list: Vec<Box<Flowable<'a, 'b> + 'a>>,
}

impl<'a: 'b, 'b> Flowable<'a, 'b> for ContTrait<'a, 'b> {
    fn flow(&'a self, dest: &mut Dest<'b>) {
        for flowable in self.list.iter() {
            flowable.flow(dest);
        }
    }
}

fn main() {
    let x1 = 15;
    let x2 = 20;
    let mut c = ContTrait { list: Vec::new() };

    let mut dest = Dest { data: Some(&x2) };
    c.list.push(Box::new(Src { data: Some(&x1) }));
    c.flow(&mut dest);
}

我正在努力实现将引用从一个结构传递到另一个结构。每次我进步一点点,就会有一个新的块。我想要实现的目标在 C++ 等语言中看起来微不足道,对于 Src 类型,如果满足特定条件,则定义一个特征 Flowable,A 中的引用将传递给 Dest 类型。我已经使用生命周期说明符玩了一段时间,以使 Rust 编译器满意。现在我还为类型 ContTrait 实现了相同的特征,它是 Flowable 的集合,并且这个 ContTrait 还实现了特征 Flowable 以迭代其中的每个对象并调用流。这是现实世界使用的简化案例。

我只是不明白为什么 Rust 编译器会报告

error[E0597]: `c` does not live long enough
  --> src\main.rs:38:5
   |
38 |   c.flow(&mut dest);
   |   ^ borrowed value does not live long enough
39 | }
   | -
   | |
   | `c` dropped here while still borrowed
   | borrow might be used here, when `c` is dropped and runs the destructor for type `ContTrait<'_, '_>

【问题讨论】:

  • 下次请运行rustfmt。还要确保错误中的行号与示例中的实际行号匹配。
  • 我看到很多&lt;'a: 'b, 'b&gt;。这是多余的,可以替换为&lt;'a&gt;,并将所有'b替换为'a
  • “我想要实现的目标在 C++[.] 等语言中看起来微不足道” 我对此表示怀疑。 Here's the nearest I could get in C++corrected Rust code。你可能在想一些更简单的东西,在 C++ 中更容易,但在 Rust 中会有更多的摩擦,比如需要一些 unsafe { ... } 或很多 .clone()s。
  • (此外,C++ 版本仍然很脆弱;for example, you could do this。Rust 版本中的显式生命周期正是使其安全的原因。在大多数情况下,Rust 的生命周期只是形式化了同样存在的规则在 C++ 中——它们只是由你而不是 Rust 强制执行。)

标签: rust lifetime borrowing


【解决方案1】:
pub trait Flowable<'a: 'b, 'b> {
    fn flow(&'a self, dest: &mut Dest<'b>);
}

这里的&amp;'a self 是问题的核心。它说对象 flow 被调用必须比 dest 参数化的生命周期更长。

main 中,你可以

c.flow(&mut dest);

并且dest 被隐式参数化为x2 的生命周期。由于您在 c 上调用 flow,因此您暗示 c 必须比 x2 寿命长,但事实并非如此。

如果您删除 trait 定义中的自引用绑定的 'aContTrait impl,代码将编译。

【讨论】:

  • 感谢您的建议和解释。
  • 根据经验:您可能不想使用&amp;'a self,大部分时间。有一些合法的情况,例如其中函数的返回值取决于self,编译器无法计算出来,但通常&amp;self 就是你想要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 2019-11-02
  • 2015-05-13
相关资源
最近更新 更多