rust - 如何解决 "Returns a value referencing data owned by the current function"(结构之间的实际依赖关系)

标签 rust borrow-checker ownership object-lifetime

我正在学习 Rust(我是一名 C++ 开发人员),但我仍在习惯借用检查器。 我有以下示例(也在 godbolt 上: https://godbolt.org/z/z873x9cPn ):

struct Foo {
    value: i32,
}

struct Bar <'a> {
    foo: &'a mut Foo,
}

struct Parent <'a> {
    foo: Foo,
    bar: Bar<'a>,
}

impl <'a> Bar <'a> {
    fn new(foo: &'a mut Foo) -> Self {
        Self {
            foo
        }
    }
}

impl <'a> Parent <'a> {
    fn new() -> Self {
        let mut foo = Foo{ value: 2};
        let bar = Bar::new(&mut foo);

        Self {
            foo,
            bar,
        }
    } 
}

fn main () {
    let _parent = Parent::new();
}

但是当尝试编译时出现错误:

error[E0515]: cannot return value referencing local variable `foo`
  --> <source>:27:9
   |
25 |           let bar = Bar::new(&mut foo);
   |                              -------- `foo` is borrowed here
26 | 
27 | /         Self {
28 | |             foo,
29 | |             bar,
30 | |         }
   | |_________^ returns a value referencing data owned by the current function

我一直在浏览其他帖子,但它们并没有完全解决这种依赖性。另外,我一直在尝试弄清楚该怎么做,但没有找到解决方案。

最好的解决方案是什么?

最佳答案

如果您在 C++ 中以与 Rust 相同的方式实现此功能,则会出现未定义的行为。 Rust 实际上在这里拯救了你。

&mut foo创建对局部函数 foo 的引用,但随后你移动 foo进入 Parent 的新实例,因此引用不再有效。 Rust 在编译时捕获了这一点。当存在对某个值的引用时,您无法移动或删除该值。

从实现复杂性的角度来看,解决这个问题的最简单方法是使用引用计数智能指针( Rc ),它将给出 BarParent Foo共享所有权 。 (这类似于 C++ std::shared_ptr 模板,并且具有几乎相同的语义。)

但是,由于您放弃了对 Foo可变引用,这让事情变得复杂。 。 Rust 不允许您获取对 Rc 所持有的值的可变引用。除非只有一个 Rc那时就存在。

您可以使用Cell来解决这个问题或RefCell ,提供 interior mutabilityRefCell更灵活,但运行时开销更大,因为它在运行时实现了 Rust 的借用规则,这意味着如果使用不正确,它也会出现 panic 。

这就是它的样子:

use std::rc::Rc;
use std::cell::RefCell;

struct Foo {
    value: i32,
}

struct Bar {
    foo: Rc<RefCell<Foo>>,
}

struct Parent {
    foo: Rc<RefCell<Foo>>,
    bar: Bar,
}

impl Bar {
    fn new(foo: Rc<RefCell<Foo>>) -> Self {
        Self {
            foo
        }
    }
}

impl Parent {
    fn new() -> Self {
        let mut foo = Rc::new(RefCell::new(Foo { value: 2 }));
        let bar = Bar::new(foo.clone());

        Self {
            foo,
            bar,
        }
    } 
}

由于您尝试创建的结构是自引用的,因此非 Rc处理这个问题的方法将涉及 pinningunsafe 。基本上你必须创建 Foo在对它进行任何引用之前,先将其放在稳定的内存位置,并且 Pin<_>需要确保值的内存位置永远不会改变。您可能仍然需要 RefCell如果您希望该值通过 Parent 都是可变的和 Bar .

关于rust - 如何解决 "Returns a value referencing data owned by the current function"(结构之间的实际依赖关系),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71729391/

相关文章:

循环中的 Rust 生命周期问题

rust - 发生移动是因为 `*arg` 的类型为 `String` ,该类型未实现 `Copy` 特征

rust - "the trait bound std::fmt::Display is not satisfied"是什么意思?

rust - 如何安抚嵌套数据结构的借用检查器?

rust - 如何在 Rust 中多线程中使用串口?

rust - 如何在遍历 Vector 时从字符串复制字符串?

c++ - 单一与共享所有权的含义

c - 如何在 Rust 中获取 C 指针的所有权并适本地删除它?

rust - 为什么 Rust Closure 在被调用之前就拥有所有权

rust - 这种借用 "Rust way"吗?