gpt4 book ai didi

rust - 在递归数据结构中使用常规引用而不是 `Box`

转载 作者:行者123 更新时间:2023-12-03 11:24:19 33 4
gpt4 key购买 nike

我是 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在这个简单的情况下工作。但是,如果我们尝试以其他方式使用这种结构,我们会遇到一些困难。例如,假设我们试图构造一个 FunctionalList然后从函数返回它:

#[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 中的每个值都必须在某个地方有一个所有者;所以如果,在这种情况下, FunctionaList不是其内部的所有者 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);
}

在这种情况下,我们调整了返回类型 make_list仅返回对 FunctionalList 的可变引用,而不是返回一个拥有的 FunctionalList ,因为现在所有权属于 arena .

关于rust - 在递归数据结构中使用常规引用而不是 `Box`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62368330/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com