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

4
在Rust 1.36中,以下代码可以编译通过:
let arr = [0 as u8; 30];
let buf: Box<[u8]> = Box::new(arr);

但是这个代码失败了,错误信息为:期望切片,但发现了一个30个元素的数组,指的是下面标记的代码:
let arr = [0 as u8; 30];
let buf: RefCell<[u8]> = RefCell::new(arr);
                         ^^^^^^^^^^^^^^^^^

谁能解释一下这种行为的不同之处?RefCellBox都将T约束为<T: ?Sized>


@trentcl 那似乎很可能是答案。谢谢。 - Chris Shain
1个回答

5

Box<T> 实现了 CoerceUnsized<U> trait,允许从 Box<T>Box<U> 的强制转换,当且仅当 T 实现了 Unsize<U> trait。 直观来说,如果 UT 的“非定长”版本,则 T 实现了 Unsize<U>。比如,当 T 实现了 Trait 时,[T; N] 实现了 Unsize<[T]>T 实现了 Unsize<dyn Trait>

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

RefCell<T> 也实现了 CoerceUnsized<U>,但它的实现相对较少。 它只能在 T 已经可以强制转换为 U 的情况下,从 RefCell<T>RefCell<U> 执行强制转换,这不包括 T: Unsize<U>

impl<T, U> CoerceUnsized<RefCell<U>> for RefCell<T> where
    T: CoerceUnsized<U>, 
CoerceUnsized<U>的强制转换应该始终在指针后面,这是因为它适用于Box<T>,但不适用于RefCell<T>。尽管称为 Ref Cell,但RefCell<T>实际上直接持有其数据。 RefCell<T>具有value:UnsafeCell<T>字段,而UnsafeCell<T>只有一个字段value:T。这里没有进行间接引用。

恰好,Unsize<U>的规则允许T:Unsize<U>RefCell<T>:Unsize<RefCell<U>>,因此我们可以通过隐藏指针来在它们之间进行强制转换。

use std::cell::RefCell;

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

这里也可以使用其他(智能)指针,例如 Box<T>Rc<T> 等等。 (playground 链接)


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