Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Defaults

Use default = <expr> inside build(...) to make a field optional in the builder. When build() is called without setting the field, the expression is evaluated and its result is used as the value.

Basic Default

use moxy::Build;

#[derive(Build, Default)]
struct Server {
    #[moxy(build(default = "localhost"))]
    pub host: String,
    #[moxy(build(default = 8080u16))]
    pub port: u16,
    #[moxy(build)]
    pub name: String,
}

// Only `name` is required; host and port fall back to their defaults.
let s = Server::new().name("api").build();
assert_eq!(s.host, "localhost");
assert_eq!(s.port, 8080u16);

// Defaults can still be overridden.
let s = Server::new().host("0.0.0.0").port(443u16).name("tls").build();
assert_eq!(s.host, "0.0.0.0");

impl Into<T> Expressions

The default expression is passed through the same Into<T> conversion used by the setter, so it does not need to be the exact field type — it only needs to implement Into<T>:

use moxy::Build;

#[derive(Build, Default)]
struct App {
    // &str → String via Into
    #[moxy(build(default = "localhost"))]
    pub host: String,

    // method call returning String — identity Into
    #[moxy(build(default = "api".to_string()))]
    pub name: String,

    // Vec::new() — Vec<String>: Into<Vec<String>>
    #[moxy(build(default = Vec::new()))]
    pub tags: Vec<String>,
}

Constants and Expressions

Any valid Rust expression works — including named constants, function calls, and more complex expressions:

use moxy::Build;

const DEFAULT_RETRIES: u32 = 3;

#[derive(Build, Default)]
struct Client {
    #[moxy(build(default = DEFAULT_RETRIES))]
    pub retries: u32,
}

let c = Client::new().build();
assert_eq!(c.retries, 3);

The expression is placed inside unwrap_or_else(|| <expr>.into()), so it is evaluated lazily — only when the field was not set.

Tip

Because defaults are evaluated lazily, expensive expressions like Vec::new() or function calls are only executed if the field was not set by the caller — there is no cost when the field is provided.