关于rust:何时使用Rc vs Box?

When to use Rc vs Box?

我有以下同时使用RcBox的代码;两者之间有什么区别?哪个更好?

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
    println!("{} {}", b1, b2);
}

游乐场链接


Rc提供共享所有权,因此默认情况下它的内容不能被突变,而Box提供独占所有权,因此允许突变:

1
2
3
4
5
6
7
8
9
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;否则,请使用Box。否则,请使用Rc(对于多线程共享用法,请使用Arc),并请记住,内部可变性将需要CellRefCell


看看描述中给出的示例,我认为这里的真正问题是"何时使用Rc&Box "(请注意"&"号)。

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

Rc情况下,每当最后一个所有者(无论是原始所有者还是任何克隆的所有者)被丢弃时,基础数据都将被丢弃(释放/释放),这就是引用计数的想法。但是,在&Box情况下,只有一个所有者:对该所有者的任何超出范围的共享引用将在所有者超出范围后立即失效。

用不同的方式讲,与Rc::clone()相反,将变量绑定到新的&Box(在示例中为let a2 = &a;)不会使它的生存期更长。

作为一个具体示例,以下内容是有效的:

1
2
3
4
5
6
7
8
9
10
11
12
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.
}

但这不是:

1
2
3
4
5
6
7
8
9
10
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.
}