2016-09-10 58 views
3

我即將給出一個特徵作爲參數來存儲它通過名爲new的構造方法。'static:std :: marker :: Sized`不滿足 - 我需要Box嗎?

用於結構類型的性狀給定爲參數這裏:

渲染 .RS

use super::shapes::Shape; 

pub struct Renderer; 

impl Renderer{ 
    pub fn set_shape<T : Shape>(&self, shape: T) -> T::Builder{ 
     T::Builder::new(shape) 
    } 
} 

然後由相關聯的類型指定的Builder的構造器將被稱爲

shapebuilder.rs

use super::shapes::Shape; 
use super::shapes::Rectangle; 

pub trait ShapeBuilder{ 
    fn new<T:Shape>(shape: T) -> Self; 
} 

pub struct RectangleBuilder{ 
    shape: Shape<Builder=RectangleBuilder> 
} 

impl ShapeBuilder for RectangleBuilder{ 
    fn new<T:Shape>(shape: T) -> Self{ 
     RectangleBuilder{ 
      shape: shape as Rectangle 
     } 
    } 
} 

在這一點上我已經想指出編譯器輸出

compiler_output

error[E0277]: the trait bound `shapes::Shape<Builder=shapebuilder::RectangleBuilder> + 'static: std::marker::Sized` is not satisfied 
    --> shapes.rs:14:6 
    | 
14 | impl Shape for Rectangle{ 
    |  ^^^^^ 
    | 
    = note: `shapes::Shape<Builder=shapebuilder::RectangleBuilder> + 'static` does not have a constant size known at compile-time 
    = note: required because it appears within the type `shapebuilder::RectangleBuilder` 
    = note: required by `shapes::Shape` 

error: aborting due to previous error 

我發現這裏的SO類似的問題這跟一些關於拳擊。我試圖將每個參數類型都填滿以解決問題。像這樣盒裝它shape: Box<T>。沒有成功。我是否需要裝箱?我瞭解編譯器無法解析特徵大小的問題,因爲特定/具體結構類型可能根據其字段/屬性具有不同的大小。但我仍然無法找到解決方案。希望它是微不足道的。


NOT involed模塊(我認爲)上市完整性

shapes.rs

use super::shapebuilder::ShapeBuilder; 
use super::shapebuilder::RectangleBuilder; 

pub trait Shape{ 
    type Builder: ShapeBuilder; 
} 

#[derive(Clone, Copy)] 
pub struct Rectangle{ 
    pub height: usize, 
    pub width: usize, 
} 

impl Shape for Rectangle{ 
    type Builder = RectangleBuilder; 
} 

lib.rs

pub mod renderer; 
mod shapes; 
mod shapebuilder; 
+2

這是你能做到的最小*例子嗎?嘗試隔離具體的問題,這將使你和我們更清楚。 – Aurora0001

+0

'renderer.rs'和'shapebuilder.rs'已經儘可能小而且是唯一的重要信息。從頭條開始的東西** NOT involed modules ... **是 - 正如我所提到的 - 只是爲了完整性,因爲人們在另一個問題上要求所有模塊自己編譯和測試它。請務必先閱讀所有標題。 – xetra11

+1

我不認爲你看到我的觀點正確 - 你現在的代碼示例並不是最小的,並且包含從其他文件導入的內容。爲了讓你的問題更清楚,你應該找到導致問題的部分代碼,並且完全擺脫其餘的部分**,以創建一個仍然存在相同問題的更簡單的例子。就目前而言,我需要將所有文件和目錄結構複製到一個項目中,以便重現您的問題,如果您將問題隔離得更多,則不需要這樣做。 – Aurora0001

回答

5

那麼,編譯器並沒有真正指出錯誤的根源。該問題是在這裏:

pub struct RectangleBuilder { 
    shape: Shape<Builder=RectangleBuilder> 
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is an unsized type! 
} 

Shape是性狀,並且用它作爲一個類型產生一個未施膠類型。我們可以將其修復以解決此錯誤:

pub struct RectangleBuilder { 
    shape: Box<Shape<Builder=RectangleBuilder>> 
} 

但是,那麼,我們該怎麼做呢?

impl ShapeBuilder for RectangleBuilder { 
    fn new<T: Shape>(shape: T) -> Self { 
     RectangleBuilder { 
      shape: shape as Rectangle 
      //  ^^^^^^^^^^^^^^^^^^ can't cast a generic type! 
     } 
    } 
} 

如果RectangleBuilder確實將準備接受任何ShapeBuilderRectangleBuilder,那麼我們刪除的演員和添加適當的約束在必要。

pub mod renderer { 
    use super::shapes::Shape; 
    use super::shapebuilder::ShapeBuilder; 

    pub struct Renderer; 

    impl Renderer { 
     pub fn set_shape<T: Shape + 'static>(&self, shape: T) -> T::Builder { 
      T::Builder::new(shape) 
     } 
    } 
} 

mod shapes { 
    use super::shapebuilder::ShapeBuilder; 
    use super::shapebuilder::RectangleBuilder; 

    pub trait Shape { 
     type Builder: ShapeBuilder; 
    } 

    #[derive(Clone, Copy)] 
    pub struct Rectangle { 
     pub height: usize, 
     pub width: usize, 
    } 

    impl Shape for Rectangle { 
     type Builder = RectangleBuilder; 
    } 
} 

mod shapebuilder { 
    use super::shapes::Shape; 

    pub trait ShapeBuilder: Sized { 
     fn new<T: Shape<Builder=Self> + 'static>(shape: T) -> Self; 
    } 

    pub struct RectangleBuilder { 
     shape: Box<Shape<Builder=RectangleBuilder> + 'static>, 
    } 

    impl ShapeBuilder for RectangleBuilder { 
     fn new<T: Shape<Builder=Self> + 'static>(shape: T) -> Self { 
      RectangleBuilder { 
       shape: Box::new(shape) 
      } 
     } 
    } 
} 

'static束縛它限制可以存儲在特定Shape實例的引用。'static意味着實現不能包含引用,除非它們的生存期爲'static

但是,如果你需要在RectangleBuilder使用Rectangle的字段,然後RectangleBuilder應該只接受Rectangle S,而不是任何形狀。我們可以再次使用關聯的類型來表達這一點。

pub mod renderer { 
    use super::shapes::Shape; 
    use super::shapebuilder::ShapeBuilder; 

    pub struct Renderer; 

    impl Renderer { 
     pub fn set_shape<T: Shape>(&self, shape: T) -> T::Builder { 
      T::Builder::new(shape) 
     } 
    } 
} 

mod shapes { 
    use super::shapebuilder::ShapeBuilder; 
    use super::shapebuilder::RectangleBuilder; 

    pub trait Shape { 
     type Builder: ShapeBuilder<Shape=Self>; 
    } 

    #[derive(Clone, Copy)] 
    pub struct Rectangle { 
     pub height: usize, 
     pub width: usize, 
    } 

    impl Shape for Rectangle { 
     type Builder = RectangleBuilder; 
    } 
} 

mod shapebuilder { 
    use super::shapes::Shape; 
    use super::shapes::Rectangle; 

    pub trait ShapeBuilder: Sized { 
     type Shape: Shape + ?Sized; 

     fn new(shape: Self::Shape) -> Self; 
    } 

    pub struct RectangleBuilder { 
     shape: Rectangle, 
    } 

    impl ShapeBuilder for RectangleBuilder { 
     type Shape = Rectangle; 

     fn new(shape: Self::Shape) -> Self { 
      RectangleBuilder { 
       shape: shape 
      } 
     } 
    } 
} 

ShapeBuilder,我們增加了一個Shape相關聯的類型,指定每個ShapeBuilder將要操作的是什麼類型的ShapeShapeBuilder::new現在使用此關聯類型來代替類型參數來指定其操作數的類型。請注意,+ ?Sized綁定是必要的,否則會有一個隱含的+ Sized綁定,Rust抱怨Shape並不意味着Sized。解決此問題的另一種方法是將: Sized添加到Shape的定義中。

pub trait Shape: Sized { 
    type Builder: ShapeBuilder<Shape=Self>; 
} 
+3

哇......這是非常明確的。 Rust真的需要非常明確地聲明事物。對於我來說,作爲一名Java開發人員很難想到這一切 - 但我很高興Rust能以這種方式工作。讓我來了解代碼的工作方式。要測試這個解決方案並將其標記爲儘快解答。謝謝 – xetra11