Dynamically Sized Types

When you create a new value in Rust, it lives in a part of memory called the stack. It’s called a stack because it gets built up from the bottom to the top, like a stack of boxes. And just like a stack of boxes, it’s easy to add things and take things off the top. The stack turns out to be a great place to store a lot of data in Rust.

However, there’s a limitation with Rust’s stack. Each one of those boxes has to be a statically sized type. That means the compiler needs to know exactly how much memory the value is going to take based only on its type.

Let’s take an example. The value 5_i32 is a 32-bit signed integer. That means it takes up exactly 4 bytes. So, Rust can store that on the stack.

Let’s take another example. Consider our beloved Fruit type:

struct Fruit {
    apples: i32,
    bananas: i32,
}

The apples and bananas fields each take up 4 bytes, for a total of 8 bytes.

And let’s take one final example, the value let y: &i32 = &x. The reference holds an address, which is 64 bits, or 8 bytes.

In these examples, we can look at just the type of the value, and know exactly how much stack space to set aside for it.

Now let’s take a string literal, "Hello". We can read the word, count the letters, and figure out that it will take up 5 bytes. Then we can look at the string literal, "Michael", and figure out that it will take up 7 bytes. The problem is that both of these have the same type, str. Therefore, it’s impossible to know just from looking at the type how much space to set aside on the stack.

This is what we call a dynamically sized type, or DST. DSTs have a few restrictions, but the big one is: they can’t be stored on the stack. However, since a reference takes up a fixed amount of space, a reference to an str can live on the stack. This is why string literals end up being &strs instead of strs.

But that still leaves us with one question: if they don’t live on the stack, where exactly do string literals live?

Get hands-on with 1200+ tech skills courses.