2016-09-10 10 views
3

Я собираюсь дать признак в качестве аргумента, чтобы сохранить его с помощью метода contructor под названием new.'static: std :: marker :: Sized` не удовлетворен - мне нужно вставить?

Черта для типа структуры приведена в качестве аргумента здесь:

визуализатора .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>. Нет успеха. Нужно ли мне вообще боксировать? Я понимаю, что компилятор не может решить размер признака, поскольку конкретные/конкретные типы структуры могут иметь разные размеры в зависимости от их поля/свойств. Тем не менее я не могу найти решение. Надеюсь, это тривиально.


НЕ выполнявшие модули (мое мнение) перечислены для полноты

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 invested 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 Если действительно будет готов принять любой Shape чей Builder является RectangleBuilder, то давайте снимем гипс и добавить соответствующие ограничения, в случае необходимости.

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.

Однако, если вам нужно использовать Rectangle «s поля в RectangleBuilder, то RectangleBuilder следует принимать только Rectangle с, а не любую форму. Мы можем снова использовать связанные типы, чтобы выразить это.

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 соответствующий тип, который определяет, какой тип Shape каждый ShapeBuilder будет работать дальше. ShapeBuilder::new теперь использует этот связанный тип вместо параметра типа, чтобы указать тип его операнда. Обратите внимание, что необходима привязка + ?Sized, потому что в противном случае существует неявный + Sized, и Rust жалуется, что Shape не означает Sized. Другой способ исправить это - добавить : Sized в определение Shape.

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

Вау ... это очень явное. Русту действительно нужно, чтобы вещи были провозглашены очень четко. Мне сложно как разработчику Java подумать обо всем этом, но я рад, что Rust работает таким образом. Позвольте мне понять, как код работает лучше. Собираюсь проверить это решение и отметить это как ответ как можно скорее. благодаря – xetra11

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

  • Нет связанных вопросов^_^