rust - 在递归数据结构中使用常规引用而不是 `Box`
问题描述
我是 Rust 的新手。当我阅读The Rust Programming Language的第 15 章时,我不明白为什么应该Box
在递归数据结构中使用 es 而不是常规引用。这本书的 15.1 解释了需要间接来避免无限大小的结构,但它没有解释为什么要使用Box
.
#[derive(Debug)]
enum FunctionalList<'a> {
Cons(u32, &'a FunctionalList<'a>),
Nil,
}
use FunctionalList::{Cons, Nil};
fn main() {
let list = Cons(1, &Cons(2, &Cons(3, &Nil)));
println!("{:?}", list);
}
上面的代码编译并产生所需的输出。似乎使用FunctionalList
在堆栈上存储少量数据效果很好。这段代码会引起麻烦吗?
解决方案
确实,FunctionalList
在这个简单的案例中的作品。但是,如果我们尝试以其他方式使用这种结构,我们会遇到一些困难。例如,假设我们尝试构造 aFunctionalList
然后从函数中返回它:
#[derive(Debug)]
enum FunctionalList<'a> {
Cons(u32, &'a FunctionalList<'a>),
Nil,
}
use FunctionalList::{Cons, Nil};
fn make_list(x: u32) -> FunctionalList {
return Cons(x, &Cons(x + 1, &Cons(x + 2, &Nil)));
}
fn main() {
let list = make_list(1);
println!("{:?}", list);
}
这会导致以下编译错误:
error[E0106]: missing lifetime specifier
--> src/main.rs:9:25
|
9 | fn make_list(x: u32) -> FunctionalList {
| ^^^^^^^^^^^^^^ help: consider giving it an explicit bounded or 'static lifetime: `FunctionalList + 'static`
如果我们按照提示添加'static
生命周期,则会收到此错误:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:10:12
|
10 | return Cons(x, &Cons(x + 1, &Cons(x + 2, &Nil)));
| ^^^^^^^^^^^^^^^^^^^^^^-----------------^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
问题是这里的内部值由隐式临时变量拥有,其范围在函数FunctionalList
末尾结束。make_list
因此,这些值将在函数末尾被删除,留下对它们的悬空引用,这是 Rust 不允许的,因此借用检查器拒绝此代码。
相反,如果FunctionalList
已经定义了Box
它的FunctionalList
组件,那么所有权就会从临时值转移到包含的值中FunctionalList
,我们可以毫无问题地返回它。
对于您的原始文件FunctionalList
,我们必须考虑的是,Rust 中的每个值都必须在某个地方拥有一个所有者;因此,如果在这种情况下, theFunctionaList
不是其内部FunctionalList
s 的所有者,那么该所有权必须位于其他地方。在您的示例中,该所有者是一个隐式临时变量,但在更复杂的情况下,我们可以使用不同类型的外部所有者。这是一个使用TypedArena
(来自typed-arena crate)来拥有数据的示例,这样我们仍然可以实现make_list
函数的变体:
use typed_arena::Arena;
#[derive(Debug)]
enum FunctionalList<'a> {
Cons(u32, &'a FunctionalList<'a>),
Nil,
}
use FunctionalList::{Cons, Nil};
fn make_list<'a>(x: u32, arena: &'a Arena<FunctionalList<'a>>) -> &mut FunctionalList<'a> {
let l0 = arena.alloc(Nil);
let l1 = arena.alloc(Cons(x + 2, l0));
let l2 = arena.alloc(Cons(x + 1, l1));
let l3 = arena.alloc(Cons(x, l2));
return l3;
}
fn main() {
let arena = Arena::new();
let list = make_list(1, &arena);
println!("{:?}", list);
}
在这种情况下,我们调整了 of 的返回类型,make_list
只返回一个对 a 的可变引用FunctionalList
,而不是返回一个owned FunctionalList
,因为现在所有权位于arena
.
推荐阅读
- php - 无法获取 PHP 查询以返回要制成数组的资源,我无权访问连接数据
- python-3.x - 不和谐.py | 如何让机器人根据你输入的内容说话?
- vim - vim 如何改变其终端模拟器的宽度?
- c - 在最短路径 C 代码中找出此分段错误 11 的原因
- many-to-many - DynamoDB MM 邻接表设计模式
- angular - angular 5 ngModel 条件绑定
- wpf - 在 WPF ListView 中一次显示多个列表?
- swift - 如何在 Swift 中的函数之外访问一个变量,然后它在 while 循环中运行?
- java - 使用 Firebase 实时数据库在重启时重置警报
- swift - Swift 4:根据字符修剪字符串的最后一个字符