我正在学习 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
),它将给出 Bar
和Parent
Foo
的共享所有权 。 (这类似于 C++ std::shared_ptr
模板,并且具有几乎相同的语义。)
但是,由于您放弃了对 Foo
的可变引用,这让事情变得复杂。 。 Rust 不允许您获取对 Rc
所持有的值的可变引用。除非只有一个 Rc
那时就存在。
您可以使用Cell
来解决这个问题或RefCell
,提供 interior mutability 。 RefCell
更灵活,但运行时开销更大,因为它在运行时实现了 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
处理这个问题的方法将涉及 pinning和unsafe
。基本上你必须创建 Foo
在对它进行任何引用之前,先将其放在稳定的内存位置,并且 Pin<_>
需要确保值的内存位置永远不会改变。您可能仍然需要 RefCell
如果您希望该值通过 Parent
都是可变的和 Bar
.
关于rust - 如何解决 "Returns a value referencing data owned by the current function"(结构之间的实际依赖关系),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71729391/