Constructors of Rust structs

The new() Method

The new() method is nothing special but it’s idiomatically used to initialise a new instance of a struct with empty fields, for example:

#[derive(Debug)]
struct Car<'a> {
    brand: &'a str,
    model: &'a str,
    color: &'a str,
}
impl<'a> Car<'a> {
    fn new() -> Self {
        Car {
            brand: "",
            model: "",
            color: "",
        }
    }
}
fn main(){
  println!("{:?}", Car::new())
}
## Car { brand: "", model: "", color: "" }

Builder Methods

For structs with many fields (some of which may be optional), it’s common to define a number of builder methods to construct them.

It’s preferable to use non-consuming builders, which takes in a mutable reference of self (&mut self) and returns the same type. This makes it easy for both chained and stepwise construction:

#[derive(Clone)]
struct Car<'a> {
    brand: &'a str,
    model: &'a str,
    color: &'a str,
}
impl<'a> Car<'a> {
    fn new() -> Self {
        Car {
            brand: "",
            model: "",
            color: "",
        }
    }
    fn brand(&mut self, brand: &'a str) -> &mut Self {
        self.brand = brand;
        self
    }
    fn model(&mut self, model: &'a str) -> &mut Self {
        self.model = model;
        self
    }
    fn color(&mut self, color: &'a str) -> &mut Self {
        self.color = color;
        self
    }
    fn drive(&self, speed: u8) {
        println!(
            "Driving {} {} {} at {} km/h",
            self.color, self.brand, self.model, speed
        )
    }
}

fn main() {
    // chained
    Car::new()
        .color("white")
        .brand("Lexus")
        .model("LC")
        .drive(60);
        
    // stepwise
    let mut car = Car::new();
    car.brand("Infinity").model("Q70L");
    car.color("black");
    car.drive(80);

    // chained construction followed by ownership transfer
    let car = Car::new()
        .brand("Nissan")
        .model("370Z")
        .color("red")
        .to_owned();
    car.drive(120);
}
## Driving white Lexus LC at 60 km/h
## Driving black Infinity Q70L at 80 km/h
## Driving red Nissan 370Z at 120 km/h

In order to construct a Car by chaining builder methods and then bind this Car to a variable, to_owned() must be called at the end of the chain to convert the mutable reference to owned type, and this requires that the ToOwned trait is implemented by Car. Adding #[derive(Clone)] above the struct definition fulfills this.