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>
时堆栈和堆上有什么) 被 build ?为什么这种“魔法”不适用于另一种未确定大小的类型,如 MaybeSized<str>
?
最佳答案
来自 &MaybeSized<String>
的转换至 &MaybeSized<dyn Display>
称为 unsized coercion .具体类型可以针对它们实现的特征强制转换为特征对象,并且这种强制在特定条件下扩展到通用结构:
Foo<..., T, ...>
toFoo<..., U, ...>
, when:
Foo
is a struct.T
implementsUnsize<U>
.- The last field of
Foo
has a type involvingT
.- If that field has type
Bar<T>
, thenBar<T>
implementsUnsized<Bar<U>>
.T
is not part of the type of any other fields.
(有关完整详细信息,请点击上面语言引用的链接。)
变量sized
存储在堆栈中,但是String
的数据分配在堆上。引用ref1
以胖指针的形式存储在堆栈中——一个指向sized
的指针连同指向 String as dyn Display
的虚拟方法表的指针允许在必要时动态调用正确的方法。
这不适用于 MaybeSized<str>
因为没有转换为 str
的未定大小的强制转换.您可以转换和 &String
到 &str
使用 deref 强制转换,但这不是我们在这里需要的——取消大小类型需要一个未调整大小的强制转换。未定尺寸的类型 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>
的安全方法.
关于rust - Rust 如何处理将 &SizedType 转换为 &UnsizedType?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55988573/