# Advanced Types Newtypes, Aliased Types, `!` type and Dynamically Sized Types ## Using Newtype Pattern for Type Safety and Abstraction Ex: Both Millimeters and Meters can be expressed with `u32`, but we would still want to differentiate. ```rust struct Millimeter(u32); struct Meter(u32); // Unless implemented, operations between Millimeter and Meters are illegal! we could use Millimeter.0 + Meter.0 but that would be an extra step again. ``` The same way, we could hide an underlying type under a wrapper and expose only the implementation needed for the user (Public and Private exports!). ```rust struct People(HashMap); impl People { // Implement functions that interact with the HashMap but only how you want! } ``` ## Creating Type Synonyms with Type Aliases ```rust type Kilometers = i32; ``` `Kilometers` will be treaded as an `i32`, we can operate between `i32` and `Kilometers`, they are just expressed differently. We can also reduce the "length" of a type with that! ```rust type Thunk = Box; fn takes_long(f: Thunk) {} fn uses_full_name(f: Box) {} // So looong ``` ## The Never Type that Never Returns `!` means *empty type* Some expressions such as `panic!()` or `continue` make somehting escape code which are expecting a value to be returned. Those expressions return a `!` that will be coerced into the expected type for then to be dropped when exiting the scope! ```rust let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, // Escapes to next iter, guess is dropped so it returns a ! which will alow execution but it is sure to be dropped }; //... impl Option { pub fn unwrap(self) -> T { match self { Some(val) => val, None => panic!("called `Option::unwrap()` on a `None` value"), // panic! stops execution, thus we drop the return and existing values! } } } ``` ## Dynamically Sized Types and `Sized` Trait ```rust let s1: str = "Hello there!"; // Illegal, we are creating a string with unknown size in stack, str is not size bound let s2: str = "Hi!"; // Different size str, ``` In Rust we would use `&str` for this type as the string will be put in binary memory and accessed as a slice from the heap. `&str` is a pointer that has `address` and `size`, which makes it a fixed type that points to a unfixed size. That is what must be done to other unknown size types. Previously we saw, that `Trait Objects` must be accessed in a similar way. Put behind a dynamic type -> `&dyn Trait` `Box` `Rc` ... We are accessing an unknown object through a pointer! By default when we do `generic` translates to `generic` which it expects the type to be of known size at compile time. To allow types with unknown size: `generic` `?Trait` is only for `?Sized`. Then every time we call a unknown size type, it must be behinmd a pointer/reference!