Skip to content

Commit

Permalink
[idioms/ctor] adds default constructor section (#280)
Browse files Browse the repository at this point in the history
Replaced the `Vec` example with `Second`. This is easier to
comprehend compared to the more complex `Vec` example. It's also
testable because it doesn't rely on `RawVec`.

Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com>
Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 21, 2021
1 parent 39a2f36 commit fa8e722
Showing 1 changed file with 93 additions and 21 deletions.
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());
/// ```
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 {
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

0 comments on commit fa8e722

Please sign in to comment.