2016-09-01 1 views
0

Я пытаюсь создать определенный шаблон строителя. Пожалуйста, не обращайте внимания на дизайн здесь - это попытка.Соответствие по типам, которые реализуют черту и, следовательно, возвращают ее

У меня есть тип Renderer, который дает метод set_shape. Тип аргумента, присвоенный вызову, должен реализовать пустую черту IsRenderable. Вход в систему метода должен отличаться между типами структур Rectangle и Circle, которые оба реализуют черту IsRenderable. Не беспокойтесь о возвращаемом типе.

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

trait IsRenderable {} 

impl IsRenderBuilder for Rectangle {} 

impl<'a> Renderer<'a> { 
    // logic that needs lifetime 'a 
    pub fn set_shape<T: IsRenderable>(shape: T) -> Box<IsRenderBuilder> { 
     match shape { 
      _ => panic!("WTF!"), 
     } 
    } 
} 

Я бы хотел сделать что-то подобное. ПСЕВДО:

match shape { 
    Rectangle => return RectangleShapeBuilder, 
    Circle => return CircleShapeBuilder, 
    _ => panic!("WTF!"), 
} 

ответ

5

Вместо использования match, вы должны добавить метод вашего IsRenderable признака, который возвращает соответствующий конструктор для конкретного Implementor.

#[derive(Clone, Copy)] 
pub struct Rectangle; 

pub trait IsRenderable { 
    fn new_builder(&self) -> Box<IsRenderBuilder>; 
} 

impl IsRenderable for Rectangle { 
    fn new_builder(&self) -> Box<IsRenderBuilder> { 
     Box::new(RectangleShapeBuilder) 
    } 
} 

struct RectangleShapeBuilder; 

pub trait IsRenderBuilder {} 

impl IsRenderBuilder for RectangleShapeBuilder {} 

pub fn set_shape<T: IsRenderable>(shape: T) -> Box<IsRenderBuilder> { 
    shape.new_builder() 
} 

Вы можете даже использовать соответствующий тип, чтобы избежать бокса IsRenderBuilder:

#[derive(Clone, Copy)] 
pub struct Rectangle; 

pub trait IsRenderable { 
    type Builder: IsRenderBuilder; 

    fn new_builder(&self) -> Self::Builder; 
} 

impl IsRenderable for Rectangle { 
    type Builder = RectangleShapeBuilder; 

    fn new_builder(&self) -> Self::Builder { 
     RectangleShapeBuilder 
    } 
} 

pub struct RectangleShapeBuilder; 

pub trait IsRenderBuilder {} 

impl IsRenderBuilder for RectangleShapeBuilder {} 

pub fn set_shape<T: IsRenderable>(shape: T) -> T::Builder { 
    shape.new_builder() 
} 
+0

Спасибо за отзыв с соответствующим типом! – xetra11

+0

Также: Я думаю, что возвращаемый тип 'set_shape' во втором фрагменте кода должен быть' :: Builder', чтобы избежать возможных конфликтов имен? –

+2

@LukasKalbertodt: Я не думаю, что конфликты имен являются проблемой, так как «T :: Builder» статически разрешен для обозначения «связанного типа« Builder »в признаке« IsRenderable », поскольку все компиляторы знают о' T' заключается в том, что он реализует 'IsRenderable'. Rust не работает, как шаблоны C++, где зависимые типы разрешаются только во время создания шаблона. Добавление другой привязки признака может вызвать двусмысленность, но тогда ее можно решить, когда возникает неоднозначность, вместо того, чтобы перейти к синтаксису в тяжелом весе. –

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