何时使用Rc而非Box?

45

我有以下代码,其中使用了RcBox,它们之间的区别是什么?哪个更好?

我有这样的代码,同时使用了RcBox,它们两者之间的区别是什么?哪一个更好呢?

use std::rc::Rc;

fn main() {
    let a = Box::new(1);
    let a1 = &a;
    let a2 = &a;
    let b = Rc::new(1);
    let b1 = b.clone();
    let b2 = b.clone();

    println!("{} {}", a1, a2); //=> 1 1
    println!("{} {}", b1, b2); //=> 1 1
}

Playground 链接

2个回答

68

Rc 提供了共享所有权,因此默认情况下不能更改其内容,而Box 提供了独占所有权,因此允许进行更改:

use std::rc::Rc;

fn main() {
    let mut a = Box::new(1);
    let mut b = Rc::new(1);

    *a = 2; // works
    *b = 2; // doesn't
}

此外,Rc 不能在线程之间发送,因为它没有实现 Send 接口。

总的来说,它们用于不同的场景:如果您不需要共享访问,请使用 Box;否则,请使用 Rc(或者对于多线程共享使用,使用 Arc),并记住您将需要使用 CellRefCell 进行内部可变性。


24

从描述中给出的示例来看,我认为真正的问题是“何时使用Rc而不是&Box”(请注意&符号)。

Rc&Box都将底层数据存储在堆上,都不能跨线程发送,并且两者都允许不可变共享(由上述示例演示)。但是,最大的区别在于Rc为您提供了一个共享(不可变)拥有的值,而对于&Box,您会获得一个共享(不可变)引用

Rc的情况下,只要最后一个所有者(无论是原始所有者还是任何克隆的所有者)被删除,底层数据就会被删除(释放/取消分配) - 这就是引用计数的想法。然而,在&Box的情况下,只有一个所有者:任何对它的共享引用将在所有者超出作用域后立即失效。

换句话说,与Rc::clone()相反,将变量绑定到新的&Box(例如在示例中的let a2 = &a;)不会使它的生命周期比以前更长。

以下是一个具体的示例:

use std::rc::Rc;

fn main() {
    let rc_clone;
    {
        let rc = Rc::new(1);
        rc_clone = rc.clone();
        // rc gets out of scope here but as a "shared owner", rc_clone
        // keeps the underlying data alive.
    }
    println!("{}", rc_clone);  // Ok.
}

但这不是:

fn main() {
    let b_ref;
    {
        let b = Box::new(1);
        b_ref = &b;
        // b gets out of scope here and since it is the only owner,
        // the underlying data gets dropped.
    }
    println!("{}", b_ref); // Compilation error: `b` does not live long enough.
}

3
你可能不想使用&Box<T>而是使用&T。Box实现了Deref<Target=T>,因此你只需使用 &*my_box 就可以得到一个 &T - Mingwei Samuel
6
我的目标只是尝试分享事物的工作原理,而不是告诉人们应该使用什么,但你说得对,不要使用 &Box<T> - sitaktif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接