Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[idioms/ctor] adds default constructor section #280

Merged
114 changes: 93 additions & 21 deletions idioms/ctor.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,106 @@
## Description

Rust does not have constructors as a language construct. Instead, the
convention is to use a static `new` method to create an object.
convention is to use an [associated function][] `new` to create an object:

## Example
```rust
/// Time in seconds.
///
/// # Example
///
/// ```
/// let s = Second::new(42);
/// assert_eq!(42, s.value());
simonsan marked this conversation as resolved.
Show resolved Hide resolved
/// ```
pub struct Second {
value: u64
}

impl Second {
// Constructs a new instance of [`Second`].
// Note this is an associated function - no self.
pub fn new(value: u64) -> Self {
simonsan marked this conversation as resolved.
Show resolved Hide resolved
Self { value }
}

/// Returns the value in seconds.
pub fn value(&self) -> u64 {
self.value
}
}
```

## Default Constructors

Rust supports default constructors with the [`Default`][std-default] trait:

```rust,ignore
// A Rust vector, see liballoc/vec.rs
pub struct Vec<T> {
buf: RawVec<T>,
len: usize,
```rust
/// Time in seconds.
///
/// # Example
///
/// ```
/// let s = Second::default();
/// assert_eq!(0, s.value());
/// ```
pub struct Second {
value: u64
}

impl Second {
/// Returns the value in seconds.
pub fn value(&self) -> u64 {
self.value
}
}

impl<T> Vec<T> {
// Constructs a new, empty `Vec<T>`.
// Note this is a static method - no self.
// This constructor doesn't take any arguments, but some might in order to
// properly initialise an object
pub fn new() -> Vec<T> {
// Create a new Vec with fields properly initialised.
Vec {
// Note that here we are calling RawVec's constructor.
buf: RawVec::new(),
len: 0,
}
impl Default for Second {
fn default() -> Self {
Self { value: 0 }
}
}
```

`Default` can also be derived if all types of all fields implement `Default`,
like they do with `Second`:

```rust
/// Time in seconds.
///
/// # Example
///
/// ```
/// let s = Second::default();
/// assert_eq!(0, s.value());
/// ```
#[derive(Default)]
pub struct Second {
value: u64
}

impl Second {
/// Returns the value in seconds.
pub fn value(&self) -> u64 {
self.value
}
}
```

**Note:** When implementing `Default` for a type, it is neither required nor
recommended to also provide an associated function `new` without arguments.

**Hint:** The advantage of implementing or deriving `Default` is that your type
can now be used where a `Default` implementation is required, most prominently,
any of the [`*or_default` functions in the standard library][std-or-default].

## See also

The [builder pattern](../patterns/creational/builder.md) for constructing objects
where there are multiple configurations.
- The [default idiom](default.md) for a more in-depth description of the
`Default` trait.

- The [builder pattern](../patterns/creational/builder.md) for constructing
objects where there are multiple configurations.

[associated function]: https://doc.rust-lang.org/stable/book/ch05-03-method-syntax.html#associated-functions
[std-default]: https://doc.rust-lang.org/stable/std/default/trait.Default.html
[std-or-default]: https://doc.rust-lang.org/stable/std/?search=or_default
simonsan marked this conversation as resolved.
Show resolved Hide resolved