Rust’s standard library has Default, which lets you define default values for structs. I looked at practical examples and how it’s implemented in libcore.

The trait looks like this:

pub trait Default {
    fn default() -> Self;
}

Examples

  1. Without Default
    If you don’t use Default, you typically write new() yourself.

    struct SomeOptions {
        foo: i32,
        bar: f32,
    }
    
    impl SomeOptions {
        fn new() -> Self {
            Self { foo: 0, bar: 0.0f32 }
        }
    }
    
    fn main() {
        let options: SomeOptions = SomeOptions::new();
    }
  2. Using Default
    The docs show this. Deriving Default lets Default::default() replace SomeOptions::new(), so you don’t need to write new()—nice and convenient.

    #[derive(Default)]
    struct SomeOptions {
        foo: i32,
        bar: f32,
    }
    
    fn main() {
        let options: SomeOptions = Default::default();
    }
  3. Overriding just part of the defaults
    Also from the docs: you can override only some fields.

    fn main() {
        let options = SomeOptions { foo: 42, ..Default::default() };
    }
  4. Implementing Default yourself
    Of course you can implement the trait manually. The docs show an enum example; here’s a struct.

    struct SomeOptions {
        foo: i32,
        bar: f32,
    }
    
    impl Default for SomeOptions {
        fn default() -> Self {
            Self { foo: 0, bar: 0.0f32 }
        }
    }
    
    fn main() {
        let options: SomeOptions = Default::default();
    }
  5. unwrap_or_default()
    Result and Option implement unwrap_or_default(). Example with Option:

    #[derive(Default, Debug, PartialEq)]
    struct SomeOptions {
        foo: i32,
        bar: f32,
    }
    
    fn main() {
        let options: SomeOptions = None.unwrap_or_default();
        assert_eq!(options, Default::default());
    }
  6. Real-world use
    glium, an OpenGL wrapper, has a large struct called DrawParameters:

    pub struct DrawParameters<'a> {
        pub depth: Depth,
        pub stencil: Stencil,
        pub blend: Blend,
        pub color_mask: (bool, bool, bool, bool),
        pub line_width: Option<f32>,
        pub point_size: Option<f32>,
        pub clip_planes_bitmask: u32,
        pub backface_culling: BackfaceCullingMode,
        pub polygon_mode: PolygonMode,
        pub multisampling: bool,
        pub dithering: bool,
        pub viewport: Option<Rect>,
        pub scissor: Option<Rect>,
        pub draw_primitives: bool,
        pub samples_passed_query: Option<SamplesQueryParam<'a>>,
        pub time_elapsed_query: Option<&'a TimeElapsedQuery>,
        pub primitives_generated_query: Option<&'a PrimitivesGeneratedQuery>,
        pub transform_feedback_primitives_written_query:
            Option<&'a TransformFeedbackPrimitivesWrittenQuery>,
        pub condition: Option<ConditionalRendering<'a>>,
        pub transform_feedback: Option<&'a TransformFeedbackSession<'a>>,
        pub smooth: Option<Smooth>,
        pub provoking_vertex: ProvokingVertex,
        pub primitive_bounding_box: (Range<f32>, Range<f32>, Range<f32>, Range<f32>),
        pub primitive_restart_index: bool,
    }

    Writing all of that each time would be painful, so Default is implemented. With it, you only set fields you want to change from the defaults.

    let params = glium::DrawParameters {
        point_size: Some(5.0),
        multisampling: false,
        ..Default::default()
        };

Details

Some types in the core library have fixed defaults. As of 1.26 they are:

typedefault
boolfalse
char'\x00'
usize0
u80
u160
u320
u640
u1280
isize0
i80
i160
i320
i640
i1280
f320
f640

Implementation in libcore

In 1.26, Default is implemented with a macro called default_impl!. Looking at the code, you’ll see the cases that correspond to the table above.

macro_rules! default_impl {
    ($t:ty, $v:expr, $doc:tt) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Default for $t {
            #[inline]
            #[doc = $doc]
            fn default() -> $t { $v }
        }
    }
}

default_impl! { bool, false, "Returns the default value of `false`" }

There are also implementations for tuples and many more.

Addendum (2018-05-29)

lo48576 told me a couple of extra points, so I’m adding them.

1

std::default::Default is imported automatically via the prelude. You can call SomeOptions::default() instead of Default::default().

Improved Example 1

#[derive(Default)]
struct SomeOptions {
    foo: i32,
    bar: f32,
}

fn main() {
    let options = SomeOptions::default();
}

2

The following code using #[derive(Default)] won’t compile. Because Option’s default is None, NoDefault itself doesn’t need to implement Default. To make it compile, implement Default manually.

NG:

// Struct with no default impl.
struct NoDefault;

#[derive(Default)]
struct SomeOptions<Content> {
    foo: Option<Content>,
    bar: f32,
}

fn main() {
    // ERROR!
    // error[E0599]: no function or associated 
    // item named `default` found for type 
    // `SomeOptions<NoDefault>` in the 
    // current scope
    let _ = SomeOptions::<NoDefault>::default(); // NG
}

OK:

// Struct with no default impl.
struct NoDefault;

struct SomeOptions<Content> {
    foo: Option<Content>,
    bar: f32,
}

impl<Content> Default for SomeOptions<Content> {
    fn default() -> Self {
        Self {
            foo: Default::default(),
            bar: Default::default(),
        }
    }
}

fn main() {
    let _ = SomeOptions::<NoDefault>::default(); // OK
}