Skip to content

finish_fn ​

Applies to: struct fields function arguments method arguments

Makes the member a positional argument on the finishing function.

TIP

Don't confuse this with the top-level #[builder(finish_fn)] attribute.

rust
use bon::Builder;

#[derive(Builder)]
struct Example {
    #[builder(finish_fn)] 
    x1: u32,

    #[builder(finish_fn)] 
    x2: u32,

    x3: u32,
}

let value = Example::builder()
    .x3(3)
    .build(1, 2); 

assert_eq!(value.x1, 1);
assert_eq!(value.x2, 2);
assert_eq!(value.x3, 3);
rust
use bon::builder;

#[builder]
fn example(
    #[builder(finish_fn)] 
    x1: u32,

    #[builder(finish_fn)] 
    x2: u32,

    x3: u32,
) -> (u32, u32, u32) {
    (x1, x2, x3)
}

let value = example()
    .x3(3)
    .call(1, 2); 

assert_eq!(value.0, 1);
assert_eq!(value.1, 2);
assert_eq!(value.2, 3);
rust
use bon::bon;

struct Example;

#[bon]
impl Example {
    #[builder]
    fn example(
        #[builder(finish_fn)] 
        x1: u32,

        #[builder(finish_fn)] 
        x2: u32,

        x3: u32,
    ) -> (u32, u32, u32) {
        (x1, x2, x3)
    }
}

let value = Example::example()
    .x3(3)
    .call(1, 2); 

assert_eq!(value.0, 1);
assert_eq!(value.1, 2);
assert_eq!(value.2, 3);

You can rename the finishing function from default build() or call() to something more readable via the top-level #[builder(finish_fn = ...)] attribute.

Ordering ​

The ordering of members annotated with #[builder(finish_fn)] matters! They will appear in the same order relative to each other in the finishing function signature. They must also be declared at the top of the members list strictly after members annotated with #[builder(start_fn)] (if any).

It ensures a consistent initialization order, making these members available in the evaluation context of expressions in #[builder(default/skip = ...)] for regular members that follow them.

Into Conversions ​

You can combine this attribute with #[builder(into)] or #[builder(on(..., into))] to add an Into conversion for the parameter.

Importantly, Into conversions for such members work slightly differently from the regular (named) members regarding the Option<T> type. There is no special handling of Option<T> type for the members annotated with #[builder(finish_fn)]. Thus, they are matched by the type pattern of on(..., into) as any other type.

TIP

In general, it's not recommended to annotate members of Option<T> type with #[builder(finish_fn)] because you can't omit setting them using the positional function call syntax.