newtype and Sized
Newtype
The orphan rule tells us that we are allowed to implement a trait on a type as long as either the trait or the type are local to our crate.
The newtype pattern can help us get around this restriction, which involves creating a new type in a tuple struct.
- 🌟
1. use std::fmt;
3. /* Define the Wrapper type */
4. __;
6. // Display is an external trait
7. impl fmt::Display for Wrapper {
8. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
9. write!(f, "[{}]", self.0.join(", "))
10. }
11. }
13. fn main() {
14. // Vec is an external type, so you cannot implement Display trait on Vec type
15. let w = Wrapper(vec![String::from("hello"), String::from("world")]);
16. println!("w = {}", w);
17. }
- 🌟 Hide the methods of the original type.
1. /* Make it workd */
2. struct Meters(u32);
4. fn main() {
5. let i: u32 = 2;
6. assert_eq!(i.pow(2), 4);
8. let n = Meters(i);
9. // The `pow` method is defined on `u32` type, we can't directly call it
10. assert_eq!(n.pow(2), 4);
11. }
- 🌟🌟 The
newtypeidiom gives compile time guarantees that the right type of value is supplied to a program.
1. /* Make it work */
2. struct Years(i64);
4. struct Days(i64);
6. impl Years {
7. pub fn to_days(&self) -> Days {
8. Days(self.0 * 365)
9. }
10. }
12. impl Days {
13. pub fn to_years(&self) -> Years {
14. Years(self.0 / 365)
15. }
16. }
18. // An age verification function that checks age in years, must be given a value of type Years.
19. fn old_enough(age: &Years) -> bool {
20. age.0 >= 18
21. }
23. fn main() {
24. let age = Years(5);
25. let age_days = age.to_days();
26. println!("Old enough {}", old_enough(&age));
27. println!("Old enough {}", old_enough(&age_days));
28. }
- 🌟🌟
1. use std::ops::Add;
2. use std::fmt::{self, format};
4. struct Meters(u32);
5. impl fmt::Display for Meters {
6. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7. write!(f, "There are still {} meters left", self.0)
8. }
9. }
11. impl Add for Meters {
12. type Output = Self;
14. fn add(self, other: Meters) -> Self {
15. Self(self.0 + other.0)
16. }
17. }
18. fn main() {
19. let d = calculate_distance(Meters(10), Meters(20));
20. assert_eq!(format!("{}",d), "There are still 30 meters left");
21. }
23. /* Implement calculate_distance */
24. fn calculate_distance
Type alias
Type alias is important to improve the readability of our code.
1. #![allow(unused)]
2. fn main() {
3. type Thunk = Box<dyn Fn() + Send + 'static>;
5. let f: Thunk = Box::new(|| println!("hi"));
7. fn takes_long_type(f: Thunk) {
8. // --snip--
9. }
11. fn returns_long_type() -> Thunk {
12. // --snip--
13. }
14. }
1. #![allow(unused)]
2. fn main() {
3. type Result<T> = std::result::Result<T, std::io::Error>;
4. }
And Unlike newtype, type alias don’t create new types, so the following code is valid:
1. #![allow(unused)]
2. fn main() {
3. type Meters = u32;
5. let x: u32 = 5;
6. let y: Meters = 5;
8. println!("x + y = {}", x + y);
9. }
- 🌟
1. enum VeryVerboseEnumOfThingsToDoWithNumbers {
2. Add,
3. Subtract,
4. }
6. /* Fill in the blank */
7. __
9. fn main() {
10. // We can refer to each variant via its alias, not its long and inconvenient
11. // name.
12. let x = Operations::Add;
13. }
- 🌟🌟 There are a few preserved aliases in Rust, one of which can be used in
implblocks.
1. enum VeryVerboseEnumOfThingsToDoWithNumbers {
2. Add,
3. Subtract,
4. }
6. impl VeryVerboseEnumOfThingsToDoWithNumbers {
7. fn run(&self, x: i32, y: i32) -> i32 {
8. match self {
9. __::Add => x + y,
10. __::Subtract => x - y,
11. }
12. }
13. }
DST and unsized type
These concepts are complicated, so we are not going to explain here, but you can find them in The Book.
- 🌟🌟🌟 Array with dynamic length is a Dynamic Sized Type ( DST ), we can’t directly use it
1. /* Make it work with const generics */
2. fn my_function(n: usize) -> [u32; usize] {
3. [123; n]
4. }
6. fn main() {
7. let arr = my_function();
8. println!("{:?}",arr);
9. }
- 🌟🌟 Slice is unsized type, but the reference of slice is not.
1. /* Make it work with slice references */
2. fn main() {
3. let s: str = "Hello there!";
5. let arr: [u8] = [1, 2, 3];
6. }
- 🌟🌟 Trait is also an unsized type
1. /* Make it work in two ways */
2. use std::fmt::Display;
3. fn foobar(thing: Display) {}
5. fn main() {
6. }
