Преобразование из &MaybeSized<String>
в &MaybeSized<dyn Display>
называется нестандартным принуждением .Конкретные типы могут быть преобразованы в объекты признаков для реализуемых ими признаков, и это принуждение распространяется на общую структуру при определенных условиях:
Foo<..., T, ...>
до Foo<..., U, ...>
, когда:
Foo
является структурой. T
реализует Unsize<U>
. - Последнее поле
Foo
имеет тип, включающий T
. - Если это поле имеет тип
Bar<T>
, то Bar<T>
реализует Unsized<Bar<U>>
. T
не является частью типа любых других полей.
(Для получения полной информации перейдите по ссылке на ссылку на язык выше.)
Переменная sized
хранится в стеке, но данные String
размещаются в куче.Ссылка ref1
хранится в стеке как жирный указатель - указатель на sized
вместе с указателем на таблицу виртуальных методов для String as dyn Display
, чтобы позволить динамический вызов нужных методов при необходимости.
Это не сработает для MaybeSized<str>
, потому что не существует нестандартного принуждения, которое преобразуется в str
.Вы можете конвертировать и &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>
.
( код на детской площадке )