在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);
^^^^^^^^^^^^^^^^^
谁能解释为什么行为不同? RefCell
和Box
都将T约束为<T: ?Sized>
。
答案 0 :(得分:4)
Box<T>
实现the trait CoerceUnsized<U>
,每当Box<T>
实现the trait Unsize<U>
时,该方法都允许从Box<U>
到T
的强制转换。直观地,如果T
是Unsize<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)