The newtype pattern is a Rust idiom that can be used to add type safety and clarity to code. At its core, the newtype pattern involves wrapping an existing Rust type (like a number or a string) inside a new struct. This might seem unnecessary at first, but the magic is that this new struct becomes a distinct type and ensures that you are using the correct type where necessary. Essentially, it’s a way to create your own Rust type.
Let’s consider this code as an example and break it down:
// Define a new type called Years that wraps around u32
struct Years(u32);
// Implement the Display trait for Years
impl std::fmt::Display for Years {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} years", self.0)
}
}
// Define a function that takes a value of type Years as an argument
fn print_age(age: Years) {
println!("You are {}", age);
}
fn main() {
// Create a value of type Years
let age = Years(25);
// Call the function with the value
print_age(age);
// Uncomment the following line to see a compile error
// print_age(25);
}
In the code above, we use the newtype pattern to create a type called Years
that represents a person’s age in years. We define the Years
type as a struct that wraps around a u32
(an unsigned 32-bit integer).
struct Years(u32);
Next, we implement the std::fmt::Display
trait for Years
. This trait allows us to format Years
values for printing.
impl std::fmt::Display for Years {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} years", self.0)
}
}
Now, we can create a function called print_age
that takes a value of type Years
as an argument.
fn print_age(age: Years) {
println!("You are {}", age);
}
In the main
function, we create a Years
value call it age
and set it to 25.
let age = Years(25);
We call the print_age
function with our age
value. This prints out the following:
You are 25 years
Finally, we have a line that is commented out. If we uncomment this line and try to pass the number 25 directly to print_age
, we will get a compile error. This is because print_age
expects a Years
value, not just any number.
// let age = 25;
// print_age(age);
This error shows us that the newtype pattern has helped us to add type safety to our code. We can be sure that the print_age
function will only be called with a valid Years
value.
The newtype pattern is a powerful tool that can be used to improve the type safety and clarity of Rust code. It is a simple concept, but it can be very effective.
Happy hacking!