Sometimes data structures have lots of or complicated fields, so that they need a number of constructors to effectively create them. Other languages would use method overloading or named arguments, but Rust doesn't have these. Instead, we can use the so-called builder pattern, which is used occasionally in Servo and the Rust standard library. The idea is that the instance construction is forwarded to an analogous Builder struct, which has a default new constructor, methods that change each of its properties, and a finish method that returns an instance of the original struct. Here is an example:
// see code in Chapter 6/code/builder_pattern.rs struct Alien { name: &'static str, health: u32, damage: u32 } struct AlienBuilder { name: &'static str, health: u32, damage: u32 } impl AlienBuilder { fn new() -> Self { AlienBuilder { name: "Walker", health: 100, damage: 10 } } fn name(&mut self, n: &'static str) -> &mut AlienBuilder { self.name = n; self } fn health(&mut self, h: u32) -> &mut AlienBuilder { self.health = h; self } fn damage(&mut self, d: u32) -> &mut AlienBuilder { self.damage = d; self } fn finish(&self) -> Alien { Alien { name: self.name, health: self.health, damage: self.damage } } } fn main() { let al1 = AlienBuilder::new() .name("Bork") .health(80) .damage(20) .finish(); println!("name: {}", al1.name); println!("health: {}", al1.health); }
This prints out the following output:
name: Bork health: 80
This way we have used the type system to enforce our concerns, and we can use the methods on the struct AlienBuilder to constrain making the struct Alien instances in any way we choose.