Здесь немного нестандартной тонкости. Основное различие между
let a: &Struct = &Struct;
let ref a: Struct = *a;
и
let a: &Trait = &Struct;
let ref a: Trait = *a;
Это выражение *a
производит значение, размер которого не известен во время компиляции. Это проявляется как ошибка при попытке сделать:
let ref a: Trait = Struct as Trait;
<anon>:6:24: 6:39 error: cast to unsized type: `Struct` as `Trait`
<anon>:6 let ref a: Trait = Struct as Trait;
^~~~~~~~~~~~~~~
<anon>:6:24: 6:30 help: consider using a box or reference as appropriate
<anon>:6 let ref a: Trait = Struct as Trait;
В общем, компилятор не может знать размер голого признака, используемого в качестве типа, как Trait
используется здесь. Это потому, что любого типа может реализовать Trait
- поэтому размер черты может быть любого размера, в зависимости от типа, который его реализует. Итак, это объясняет, почему let ref a: Trait = Struct
и let a: &Struct = &Struct; let ref a: Trait = *a
не работают, потому что отливка Struct
на Trait
- это нестандартный литой.
А почему ваша рабочая черта фрагмент кода работает, глядя на MIR для этих двух примеров, мы можем видеть, что компилятор обрабатывает два вышеупомянутых задания немного по-другому:
let a: &Struct = &Struct;
let ref a: Struct = *a;
bb0: {
tmp1 = Struct;
tmp0 = &tmp1;
var0 = &(*tmp0);
var1 = &(*var0);
return =();
goto -> bb1;
}
let a: &Trait = &Struct;
let ref a: Trait = *a;
bb0: {
tmp2 = Struct;
tmp1 = &tmp2;
tmp0 = &(*tmp1);
var0 = tmp0 as &'static Trait + 'static (Unsize);
var1 = &(*var0);
return =();
goto -> bb1;
}
Мы видим, что компилятор должен сделать отливку до объекта объекта&'static Trait + 'static
, чтобы удовлетворить неявное принуждение от &Struct
до &Trait
. Оттуда шаблон ref просто var1 = &(*var0);
, который в этом случае является простым назначением от объекта-объекта var0
объекту-объекту var1
.
Это похоже на MIR, сгенерированный этой функция:
fn stuff() {
let sized = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let slice : &[u8] = &sized;
let ref other_slice = *slice;
}
bb0: {
var0 = [const 1u8, ..., const 0u8];
tmp2 = &var0;
tmp1 = &(*tmp2);
var1 = tmp1 as &'static [u8] (Unsize);
var2 = &(*var1);
return =();
goto -> bb1;
}
Поскольку тип [u8]
является несортированным, он делает подобный бросок к ломтику, который очень похож на макете к объекту признака , В конечном счете, компилятор допускает код, который не вводит никаких неспециализированных локалей.
Как вы получаете выход MIR ?? –
, так что в основном это означает, что rustc не может не использовать ссылки rvalue, а только фактические ссылки. @PiotrZolnierek: есть кнопка 'MIR' на http://play.rust-lang.org –