Newtype
Newtype is a design pattern that allows you to create a new type that is distinct from its original type. This pattern is useful when you want to add some additional functionality to an existing type without creating a new type from scratch.
use std::fmt::Display; // Create Newtype Password to override the Display trait for String struct Password(String); impl Display for Password { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "****************") } } fn main() { let unsecured_password: String = "ThisIsMyPassword".to_string(); let secured_password: Password = Password(unsecured_password.clone()); println!("unsecured_password: {unsecured_password}"); println!("secured_password: {secured_password}"); }
Advantages
- Allows you to create a new type that is distinct from its original type.
- Provides a way to add additional functionality to an existing type without creating a new type from scratch.
- Helps in type safety by preventing accidental misuse of the original type.
- Improves code readability by giving a descriptive name to the new type.
- Enables you to implement traits for the new type without affecting the original type.
Disadvantages
- Requires additional boilerplate code to define the newtype and implement traits for it.
- May lead to code duplication if the newtype needs to implement the same traits as the original type.
- Can introduce confusion if the newtype is not used consistently throughout the codebase.
When to Use
- When you want to create a new type that is distinct from its original type.
- When you need to add additional functionality to an existing type without modifying the original type.
- When you want to improve type safety by preventing accidental misuse of the original type.
- When you need to implement traits for a specific use case without affecting the original type.
Example Use Cases
- Creating a new type to represent a secure version of an existing type (e.g., Password).
- Wrapping a primitive type to provide additional validation or formatting (e.g., Email, PhoneNumber).
- Defining a new type to represent a specific domain concept (e.g., UserId, ProductId).
- Implementing traits for a specific use case without affecting the original type (e.g., Display, Debug).