In this blog, we will discuss the advanced types available in Rust.

Creating Type Synonyms with Type Aliases
Rust provides the ability to declare a type alias to give an existing type another name. For this, we use the type
keyword. For example, we can create the alias Kilometers
to i32
like so:
type Kilometers = i32;
Values that have the type Kilometers
will be treated the same as values of type i32
:
type Kilometers = i32;
let var_1: i32 = 5;
let var_2: Kilometers = 5;
println!("Result = {}", var_1 + var_2);
Because Kilometers
and i32
are the same type, we can add values of both types and we can pass Kilometers
values to functions that take i32
parameters. However, using this method, we don’t get the type checking benefits that we get from the newtype pattern discussed earlier.
The main use case for type synonyms is to reduce repetition. For example, we might have a lengthy type like this:
Box<dyn Fn() + Send + 'static>
Writing this lengthy type in function signatures and as type annotations all over the code can be tiresome and error-prone.
let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));
fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {
// --snip--
}
fn returns_long_type() -> Box<dyn Fn() + Send + 'static> {
// --snip--
}
A type alias makes this code more manageable by reducing the repetition.
The Never Type that Never Returns
Rust has a special type named !
that’s known in type theory lingo as the empty type because it has no values. We prefer to call it the never type because it stands in the place of the return type when a function will never return. Here is an example:
fn bar() -> ! {
// --snip--
panic!();
}
This code is read as “the function bar
returns never.” Functions that return never are called diverging functions. We can’t create values of the type !
so bar
can never possibly return.
Dynamically Sized Types
Due to Rust’s need to know certain details, such as how much space to allocate for a value of a particular type, there is a corner of its type system that can be confusing: the concept of dynamically sized types. Sometimes referred to as DSTs or unsized types, these types let us write code using values whose size we can know only at runtime.
Let’s dig into the details of a dynamically sized type called str
. That’s right, not &str
, but str
on its own, is a DST. We can’t know how long the string is until runtime, meaning we can’t create a variable of type str
, nor can we take an argument of type str
. Consider the following code, which does not work:
let s1: str = "Hello there!";
let s2: str = "How's it going?";
Rust needs to know how much memory to allocate for any value of a particular type, and all values of a type must use the same amount of memory.
So what do we do? In this case, you already know the answer: we make the types of s1
and s2
a &str
rather than a str
.
If you want to read more content like this? Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.





