我正在学习 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
创建对 function-local 的引用foo
,但随后您进入 foo
的新实例Parent
,因此该引用不再有效。Rust 在编译时捕捉到了这一点。当有对它的引用时,您不能移动或删除一个值。
从实现复杂性的角度来看,解决这个问题的最简单方法是使用引用计数智能指针 ( ) ,Rc
它将授予Bar
和Parent
共享. Foo
(这类似于 C++std::shared_ptr
模板,并且具有几乎相同的语义。)
但是,由于您放弃了对Foo
. Rust 不允许你获得对 an 持有的值的可变引用,Rc
除非此时只有一个 Rc
存在。
你可以用Cell
or来解决这个问题RefCell
,它提供了内部可变性。RefCell
更灵活但有更多的运行时开销,因为它在运行时实现了 Rust 的借用规则,这意味着如果你不正确地使用它也会出现恐慌。
这就是它的样子:
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
处理此问题的非方法将涉及固定和unsafe
. 基本上,Foo
在对它进行任何引用之前,您必须在一个稳定的内存位置创建它,并且Pin<_>
需要确保一个值的内存位置永远不会改变。RefCell
如果您希望值通过Parent
和可变,您可能仍然需要Bar
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句