2017-01-12 44 views
3

下面的代碼將無法編譯這個錯誤是由於兩個實例:鏽特質對象轉換

error[E0277]: the trait bound Self: std::marker::Sized is not satisfied

爲什麼Sized在這種情況下,需要既&self&Any是指針和我不明白操作不需要知道實現特徵的結構的大小,它只需要知道指針本身以及它正在轉換的類型,因爲&self在特徵中實現時是通用的。

我認爲這可能是編譯器實施不必要的限制的一個實例,我考慮過提交rust-lang GitHub repo的問題,但我想我應該看看是否有人知道我以前不知道的東西去申請一個問題。

use std::any::Any; 

trait Component: Any { 
    fn as_any(&self) -> &Any { 
     self 
    } 

    fn as_any_mut(&mut self) -> &mut Any { 
     self 
    } 
} 

對此的另一種方法是使as_any()as_any_mut()所需的功能對於實現這一特性的結構,但對於那些結構的實施將始終是完全按照此處顯示到每一個人的性格,導致幾個實例相同的樣板代碼。

+0

我刪除了我的答案,因爲我找不到足夠快的文檔鏈接。然而,我的理解是,性狀中的「自我」是未定義的,沒有明確地將你的特徵標記爲「Sized」,編譯器會將其視爲未確定和錯誤。 –

+1

我認爲制定所需的方法是最好的選擇。至少我以前見過這種模式。爲了避免重複的代碼,你可以編寫一個簡單的宏'impl_conversion_functions!()'或類似的東西。 –

回答

6

動態大小的類型也可以實現特徵。特別是,當您定義一個對象安全特徵時,編譯器還會定義一個動態大小的類型,其名稱與該特徵的名稱相同,從而可以使用對象類型,如&Component

對象類型,如&Component&Any不只是普通的指針;他們是胖指針。胖指針將指向數據和另一條數據的指針組合起來:對於對象類型,它是指向vtable的指針;對於切片,這是切片的長度。

當從常規指針鑄件(例如&Button)到對象類型,則編譯器靜態地知道哪個V表把在脂肪指針(例如Button的VTable爲Any)。另一方面,Rust不支持從對象類型轉換爲另一種對象類型(例如從&Component&Any),因爲對象中沒有足夠的數據來初始化新的胖指針。這就是爲什麼編譯器會將此照會錯誤消息:

= note: required for the cast to the object type `std::any::Any + 'static` 

有兩種方法來解決這個問題:

  1. 要求所有類型的實施ComponentSized

    trait Component: Any + Sized { 
        fn as_any(&self) -> &Any { 
         self 
        } 
    
        fn as_any_mut(&mut self) -> &mut Any { 
         self 
        } 
    } 
    

    這會導致您無法使用對象類型,例如&ComponentBox<Component>

  2. 充分利用as_anyas_any_mut方法僅當SelfSized

    trait Component: Any { 
        fn as_any(&self) -> &Any 
         where Self: Sized 
        { 
         self 
        } 
    
        fn as_any_mut(&mut self) -> &mut Any 
         where Self: Sized 
        { 
         self 
        } 
    } 
    

    這樣,你仍然可以使用對象類型爲特質,但你不能打電話給as_anyas_any_mut上他們。

+0

這是有道理的。不幸的是,對於我的特殊情況,我確實需要能夠在特徵對象上調用這些函數。我會看看我能否找到另一種方式 –

4

我發現我認爲是一個不需要新編譯器功能的優秀解決方案。

pub trait Component { 
    // ... 
} 

pub trait ComponentAny: Component + Any { 
    fn as_any(&self) -> &Any; 
    fn as_any_mut(&mut self) -> &mut Any; 
} 

impl<T> ComponentAny for T 
    where T: Component + Any 
{ 
    fn as_any(&self) -> &Any { 
     self 
    } 

    fn as_any_mut(&mut self) -> &mut Any { 
     self 
    } 
} 

從這裏,我只想改變我的所有API接受ComponentAny而不是Component。由於Any自動執行任何'static類型,ComponentAny現在自動實現'static類型,實現Component。感謝Is there a way to combine multiple traits in order to define a new trait?的想法。