Crate derive_new
source ·Expand description
§A custom derive implementation for #[derive(new)]
A derive(new)
attribute creates a new
constructor function for the annotated
type. That function takes an argument for each field in the type giving a
trivial constructor. This is useful since as your type evolves you can make the
constructor non-trivial (and add or remove fields) without changing client code
(i.e., without breaking backwards compatibility). It is also the most succinct
way to initialise a struct or an enum.
Implementation uses macros 1.1 custom derive (which works in stable Rust from 1.15 onwards).
§Examples
Cargo.toml:
[dependencies]
derive-new = "0.5"
Include the macro:
use derive_new::new;
fn main() {}
Generating constructor for a simple struct:
use derive_new::new;
#[derive(new)]
struct Bar {
a: i32,
b: String,
}
fn main() {
let _ = Bar::new(42, "Hello".to_owned());
}
Default values can be specified either via #[new(default)]
attribute which removes
the argument from the constructor and populates the field with Default::default()
,
or via #[new(value = "..")]
which initializes the field with a given expression:
use derive_new::new;
#[derive(new)]
struct Foo {
x: bool,
#[new(value = "42")]
y: i32,
#[new(default)]
z: Vec<String>,
}
fn main() {
let _ = Foo::new(true);
}
To make type conversion easier, #[new(into)]
attribute changes the parameter type
to impl Into<T>
, and populates the field with value.into()
:
#[derive(new)]
struct Foo {
#[new(into)]
x: String,
}
let _ = Foo::new("Hello");
For iterators/collections, #[new(into_iter = "T")]
attribute changes the parameter type
to impl IntoIterator<Item = T>
, and populates the field with value.into_iter().collect()
:
#[derive(new)]
struct Foo {
#[new(into_iter = "bool")]
x: Vec<bool>,
}
let _ = Foo::new([true, false]);
let _ = Foo::new(Some(true));
Generic types are supported; in particular, PhantomData<T>
fields will be not
included in the argument list and will be initialized automatically:
use derive_new::new;
use std::marker::PhantomData;
#[derive(new)]
struct Generic<'a, T: Default, P> {
x: &'a str,
y: PhantomData<P>,
#[new(default)]
z: T,
}
fn main() {
let _ = Generic::<i32, u8>::new("Hello");
}
For enums, one constructor method is generated for each variant, with the type name being converted to snake case; otherwise, all features supported for structs work for enum variants as well:
use derive_new::new;
#[derive(new)]
enum Enum {
FirstVariant,
SecondVariant(bool, #[new(default)] u8),
ThirdVariant { x: i32, #[new(value = "vec![1]")] y: Vec<u8> }
}
fn main() {
let _ = Enum::new_first_variant();
let _ = Enum::new_second_variant(true);
let _ = Enum::new_third_variant(42);
}
§Setting Visibility for the Constructor
By default, the generated constructor will be pub
. However, you can control the visibility of the constructor using the #[new(visibility = "...")]
attribute.
§Public Constructor (default)
use derive_new::new;
#[derive(new)]
pub struct Bar {
a: i32,
b: String,
}
fn main() {
let _ = Bar::new(42, "Hello".to_owned());
}
§Crate-Visible Constructor
use derive_new::new;
#[derive(new)]
#[new(visibility = "pub(crate)")]
pub struct Bar {
a: i32,
b: String,
}
fn main() {
let _ = Bar::new(42, "Hello".to_owned());
}
§Private Constructor
use derive_new::new;
#[derive(new)]
#[new(visibility = "")]
pub struct Bar {
a: i32,
b: String,
}
fn main() {
// Bar::new is not accessible here as it is private
let _ = Bar::new(42, "Hello".to_owned()); // This will cause a compile error
}