在递归数据结构中使用常规引用而不是`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在这种简单情况下作品是可行的但是,如果尝试以其他方式使用此结构,则会遇到一些困难。例如,假设我们尝试构造a 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不允许这样做,因此借用检查器将拒绝此代码。

相反,如果FunctionalListBox对其FunctionalList组成部分进行了定义,那么所有权将从临时值移到contains FunctionalList,并且我们将能够毫无问题地返回它。

对于您的原件FunctionalList,我们必须考虑的是Rust中的每个值都必须在某处拥有所有者。因此,如果在这种情况下(FunctionaList)不是其内部FunctionalLists的所有者,则该所有权必须位于其他地方。在您的示例中,该所有者是一个隐式临时变量,但是在更复杂的情况下,我们可以使用其他类型的外部所有者。这是一个使用TypedArena(来自类型区域板条箱)拥有数据的示例,因此我们仍然可以实现该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使其仅返回对a的可变引用FunctionalList,而不返回拥有的FunctionalList,因为现在所有权位于中arena

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章