2017-01-12 19 views
0

На основе следующих примеров, его можно написать накопление шаблон с цепью, методом вызывает в Русте, который либо проходит по значению или по ссылке (с пожизненным спецификатором)Как написать идиоматический шаблон построения с цепными вызовами метода в Rust?

шаблон строитель в Rust может выглядеть примерно так:

ui::Button::new() 
    .label("Test") 
    .align(Align::Center) 
    .build(); 

При написании идиоматической ржавчины существует сильное предпочтение одному другому.

Есть ли хороший пример того, как писать это в Rust?

+2

Хотя я не являюсь поклонником шаблона построителя, я бы просто выполнил простой подход из книги [Rust book] (https://doc.rust-lang.org/book/method-syntax.html# строитель-шаблон). Это довольно идиоматично. – ljedrz

+0

Также не * особенно * вентилятор, входящий в код Python, который использовал стиль ключевого слова, например: 'ui.button (label =" Test ", align = 'CENTER')' style, поэтому ищет что-то подобное в Rust. – ideasman42

+0

@ ideaman42: Rust имеет 'Button {label =" Test ", align =" CENTER ", .. Default :: default()}' syntax :) –

ответ

1

Я видел шаблон строителя, который в основном реализовывался путем принятия права собственности на Builder при его изменении и по ссылке для build(). Например,

#[derive(Debug, Eq, PartialEq)] 
struct Foo { 
    value: usize, 
} 

struct FooBuilder { 
    foos: usize, 
    bars: usize, 
} 

impl FooBuilder { 
    fn new() -> FooBuilder { 
     FooBuilder { 
      foos: 0, 
      bars: 0, 
     } 
    } 
    fn set_foos(mut self, foos: usize) -> FooBuilder { 
     self.foos = foos; 
     self 
    } 
    fn set_bars(mut self, bars: usize) -> FooBuilder { 
     self.bars = bars; 
     self 
    } 
    fn build(&self) -> Foo { 
     Foo { 
      value: self.foos + self.bars, 
     } 
    } 
} 

fn main() { 
    let foo = FooBuilder::new() 
     .set_foos(2) 
     .set_bars(3) 
     .build(); 
    assert_eq!(foo, Foo { value: 5 }); 
} 

Try on Rust Playground

Это делает сцепление простым, позволяя при этом повторное использование строителя.

+1

Вместо этого вместо этого используется измененная ссылка для передачи строителя (без времени жизни), см. [Шаблон Builder] (https: //doc.rust-lang.org/book/method-syntax.html#builder-pattern). Я ожидаю, что это будет эффективно. –

+1

А, и интересно ... Я * также * не согласен (как с книгой, так и с вами) по поводу того, как '' self''''''''''. Поместите 'String' в' FooBuilder', и вы будете вынуждены «клонировать» его в 'build', даже если никто, который повторно использует экземпляр строителя ... это явно расточительно. –

4

Есть на самом деле два компромиссные:

  • должен именованный сеттер принимать self по значению или по ссылке?
  • следует принять окончательный метод buildself по значению или ссылке?

Моя рекомендация:

  • изменяемые ссылки для сеттеров
  • значения для метода build

Это немного отличается от Builder Pattern, представленных в Rust книге, которая использует ссылку в build.


Зачем передавать изменчивую ссылку для сеттеров?

Хотя компилятор может оптимизировать на ходы, вызванные вызовом fn label(self, &str) -> ButtonBuilder, не гарантируется.

С другой стороны, изменяемый ссылочный путь уже оптимален, поэтому вам не нужно полагаться на оптимизатор.


Почему проходя по значению для окончательного build?

Для строителей только состоящих из Copy полеев, нет никакой разницы между build с self или &self.

Однако, как только застройщик содержит не Copy полей, прохождение &self по build требует глубокого клонирования этих полей.

С другой стороны, минуя self по значению позволяет build перемещать поля, избегая ненужных копий.

Если вы хотите повторно использовать строитель, тогда строитель должен реализовать Clone.