2016-03-17 2 views
3

У нас есть noncopyable типа A и черта T определенной как это:Почему `пусть иая а: Черта = Struct` запрещено

struct Struct; 
trait Trait {} 
impl Trait for Struct {} 

Если мы создаем &Struct и deref, мы получаем ссылку RValue что мы можем использовать, чтобы инициализировать по-реф связывания:

let a: &Struct = &Struct; 
let ref a: Struct = *a; 

мы также можем непосредственно инициализировать что исх связывания:

let ref a: Struct = Struct; 

Но если мы заявляем о нашем переменном связывании требуют ссылок, только первый фрагмент кода работает

let a: &Trait = &Struct; 
let ref a: Trait = *a; 

Попытку сделать это непосредственно

let ref a: Trait = Struct; 

Или, проходя через петлю

let a: &Struct = &Struct; 
let ref a: Trait = *a; 

или

let ref a: Trait = *&Struct; 

Сообщите нам об ошибке mismatched types. Очевидно, что они не одного типа, но вывод работает для ссылок.

Это просто не реализовано (еще?) Или есть более глубокая причина, по которой это запрещено?

ответ

4

Здесь немного нестандартной тонкости. Основное различие между

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] является несортированным, он делает подобный бросок к ломтику, который очень похож на макете к объекту признака , В конечном счете, компилятор допускает код, который не вводит никаких неспециализированных локалей.

+0

Как вы получаете выход MIR ?? –

+0

, так что в основном это означает, что rustc не может не использовать ссылки rvalue, а только фактические ссылки. @PiotrZolnierek: есть кнопка 'MIR' на http://play.rust-lang.org –

Смежные вопросы