Box<T> 和 RefCell<T> 构造函数之间的行为差​​异

Chr*_*ain 4 rust

在 Rust 1.36 中,编译如下:

let arr = [0 as u8; 30];
let buf: Box<[u8]> = Box::new(arr);
Run Code Online (Sandbox Code Playgroud)

但这失败了,并出现错误:expected slice, found array of 30 elements引用带下划线的代码:

let arr = [0 as u8; 30];
let buf: RefCell<[u8]> = RefCell::new(arr);
                         ^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

谁能解释为什么行为不同?和RefCellBox将 T 约束为<T: ?Sized>

SCa*_*lla 5

Box<T>实现该特征CoerceUnsized<U>,该特征允许在实现该特征时从 强制转换Box<T>为。直观地说,实现if是 的“未调整大小”版本。例如,实现并在实现时实现。Box<U>TUnsize<U>TUnsize<U>UT[T; N]Unsize<[T]>TUnsize<dyn Trait>TTrait

impl<T, U> CoerceUnsized<Box<U>> for Box<T> where
    T: Unsize<U> + ?Sized,
    U: ?Sized, 
Run Code Online (Sandbox Code Playgroud)

RefCell<T>也实现了CoerceUnsized<U>,但实现更加有限。如果已经可以强制到,它只能执行从RefCell<T>到 的强制转换,其中不包括。RefCell<U>TUT: Unsize<U>

impl<T, U> CoerceUnsized<RefCell<U>> for RefCell<T> where
    T: CoerceUnsized<U>, 
Run Code Online (Sandbox Code Playgroud)

这里的原因是后面的强制CoerceUnsized<U>应该总是在指针后面。这适用于Box<T>,但不适用于RefCell<T>RefCell<T>尽管被称为参考单元,但实际上直接保存其数据。RefCell<T>有字段value: UnsafeCell<T>并且UnsafeCell<T>只有一个字段value: T。这里没有发生间接的情况。

碰巧的是, 的规则确实Unsize<U>允许RefCell<T>: Unsize<RefCell<U>>when T: Unsize<U>,因此如果我们隐藏在指针后面,我们可以在它们之间进行强制。

use std::cell::RefCell;

fn main() {
    let _: &mut RefCell<[u8]> = &mut RefCell::new([0; 30]);
}
Run Code Online (Sandbox Code Playgroud)

其他(智能)指针也可以在这里工作。Box<T>Rc<T>(游乐场链接)