如何解决 "Returns a value referencing data owned by the current function" (结构之间的实际依赖关系)
How to solve "Returns a value referencing data owned by the current function" (Actual depenecies between structs)
我正在学习 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 在编译时捕捉到了这一点。当存在对值的引用时,您不能移动或删除该值。
从实现复杂性的角度来看,最简单 的解决方法是使用 reference-counted 智能指针 (Rc
),它会给出 Bar
和 Parent
共享 Foo
的所有权。 (这类似于 C++ std::shared_ptr
模板,并且具有几乎相同的语义。)
但是,由于您放弃了对 Foo
的 mutable 引用,所以这很复杂。 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,
}
}
}
由于您尝试创建的结构是 self-referential,因此处理此问题的非 Rc
方法将涉及 pinning 和 unsafe
。基本上,在对它进行任何引用之前,您必须在稳定的内存位置创建 Foo
,并且需要 Pin<_>
来确保值的内存位置永远不会改变。如果您希望值通过 Parent
和 Bar
.
可变,您可能仍然需要 RefCell
我正在学习 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 在编译时捕捉到了这一点。当存在对值的引用时,您不能移动或删除该值。
从实现复杂性的角度来看,最简单 的解决方法是使用 reference-counted 智能指针 (Rc
),它会给出 Bar
和 Parent
共享 Foo
的所有权。 (这类似于 C++ std::shared_ptr
模板,并且具有几乎相同的语义。)
但是,由于您放弃了对 Foo
的 mutable 引用,所以这很复杂。 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,
}
}
}
由于您尝试创建的结构是 self-referential,因此处理此问题的非 Rc
方法将涉及 pinning 和 unsafe
。基本上,在对它进行任何引用之前,您必须在稳定的内存位置创建 Foo
,并且需要 Pin<_>
来确保值的内存位置永远不会改变。如果您希望值通过 Parent
和 Bar
.
RefCell