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/

10-10 18:34