2016-03-17 21 views
3

我們有一個不可複製型A和這樣定義的特徵T爲什麼是'讓裁判一:性狀= Struct`禁止

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

如果我們創建一個&Struct和DEREF它,我們得到一個右值引用我們可以用它來初始化一個由-REF結合:

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 = Structlet 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不能取消右值引用,但只能實際引用。 @PiotrZolnierek:http://play.rust-lang.org上有一個「MIR」按鈕 –

相關問題