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

时间:2019-08-19 20:49:10

标签: rust

在Rust 1.36中,以下编译:

let arr = [0 as u8; 30];
let buf: Box<[u8]> = Box::new(arr);

但此操作失败,错误:expected slice, found array of 30 elements引用带下划线的代码:

let arr = [0 as u8; 30];
let buf: RefCell<[u8]> = RefCell::new(arr);
                         ^^^^^^^^^^^^^^^^^

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

1 个答案:

答案 0 :(得分:4)

Box<T>实现the trait CoerceUnsized<U>,每当Box<T>实现the trait Unsize<U>时,该方法都允许从Box<U>T的强制转换。直观地,如果TUnsize<U>的“未定尺寸”版本,则U实现T。例如,当[T; N]实现Unsize<[T]>时,T实现Unsize<dyn Trait>,而T实现Trait

impl<T, U> CoerceUnsized<Box<U>> for Box<T> where
    T: Unsize<U> + ?Sized,
    U: ?Sized, 

RefCell<T>也实现了CoerceUnsized<U>,但实现的局限性更大。仅当RefCell<T>已被强制转换为RefCell<U>(不包括T的情况下,它才能从U强制转换为T: Unsize<U>

impl<T, U> CoerceUnsized<RefCell<U>> for RefCell<T> where
    T: CoerceUnsized<U>, 

这里的原因是CoerceUnsized<U>后面的强制应该始终在指针后面。这适用于Box<T>,但不适用于RefCell<T>RefCell<T>尽管被称为 Ref Cell,但实际上直接保存其数据。 RefCell<T>具有字段value: UnsafeCell<T>,而UnsafeCell<T>仅具有单个字段value: T。这里没有间接操作。

实际上,Unsize<U>的规则在RefCell<T>: Unsize<RefCell<U>>时确实允许T: Unsize<U>,因此,如果我们躲在指针后面,我们可以在它们之间进行强制。

use std::cell::RefCell;

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

其他(智能)指针也可以在这里工作。 Box<T>Rc<T>等。(playground link)