Я попытаюсь объяснить, какие преобразования (приведения) происходят в вашем коде.
Существует черта маркера с именем Unsize
, которая между другими:
Unsize реализован для:
T
равно Unsize<Trait>
при T: Trait
.
- [...]
Эта черта, AFAIK, не используется непосредственно для принуждения. Вместо этого используется CoerceUnsized
. Эта черта реализована во многих случаях, некоторые из них вполне ожидаемы, такие как:
impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
where
'b: 'a,
T: Unsize<U> + ?Sized,
U: ?Sized
, который используется для приведения &i32
в &Fooer
.
Интересная, не очень очевидная реализация этой черты, которая влияет на ваш код:
impl<T, U> CoerceUnsized<Box<U>> for Box<T>
where
T: Unsize<U> + ?Sized,
U: ?Sized
Это, вместе с определением маркера Unsize
, может быть в некоторой степени читаться как: , если U
является признаком и T
реализует U
, тогда Box<T>
может быть приведен к Box<U>
.
О вашем последнем вопросе:
Есть ли способ создать Box<Fooer>
непосредственно из i32
? Если нет: почему бы и нет?
Не то, что я знаю. Проблема заключается в том, что Box::new(T)
требуется значение размера, поскольку переданное значение перемещается в поле, а значения без размера не могут быть перемещены.
На мой взгляд, самый простой способ сделать это - просто написать:
let c = Box::new(42) as Box<Fooer>;
То есть вы создаете Box
правильного типа, а затем приводите его к типу без размера (обратите внимание, что он выглядит очень похоже на ваш d
пример).