struct MaybeSized<T: ?Sized> {
v: T,
}
fn main() {
let sized = MaybeSized {
v: "sized".to_string(),
};
use std::fmt::Display;
{
// what exactly happens here?
let ref1: &MaybeSized<Display> = &sized;
}
{
// why this fails to compile?
let ref2: &MaybeSized<str> = &sized;
}
}
MaybeSize<String>
是一个大小类型;创建ref1 : &MaybeSized<Display>
时,堆栈和堆上的内容是什么?为什么这种“魔术”对像MaybeSized<str>
这样的其他未调整大小的类型不起作用? 最佳答案
从&MaybeSized<String>
到&MaybeSized<dyn Display>
的转换称为unsized coercion。可以将具体类型强制转换为它们实现的特征的特征对象,并且这种强制在某些条件下扩展到通用结构:
(有关完整的详细信息,请单击上面的语言引用的链接。)
变量sized
存储在堆栈上,但是String
的数据分配在堆上。引用ref1
作为胖指针存储在堆栈上–指向sized
的指针以及指向String as dyn Display
的虚拟方法表的指针,以便在必要时动态调用正确的方法。
这对于MaybeSized<str>
不起作用,因为没有大小不定的强制转换为str
。您可以使用deref强制转换并将&String
转换为&str
,但这不是我们所需要的–调整大小的类型大小需要调整大小。无大小的MaybeSized<str>
类型由实际的字符串数据组成,而MaybeSized<String>
由长度,容量和指向堆的指针组成,因此无法使内存布局匹配。
但是,还有其他一些可行的情况,例如
let a = MaybeSized { v: [65u8, 66, 67]};
let b: &MaybeSized<[u8]> = &a;
可以正常工作,因为从
[u8; 3]
到[u8]
有不定大小的强制。如果您确实要执行以下操作,则可以使用不安全的代码将其转换为&MaybeSized<str>
:let c: &MaybeSized<str> = unsafe { &*(b as *const _ as *const _) };
我想不出一种创建
&MaybeSized<str>
的安全方法。(Code on the playground)
关于rust - Rust如何处理将&SizedType转换为&UnsizedType的问题?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55988573/