Advanced Types in Rust are quite helpful

Reading Time: 3 minutes

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

The Rust logo has some rough nodes · Issue #2 · rust-lang/rust-artwork ·  GitHub

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--

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: