You might have heard of
Sized before. A sized type is one that always has the same size in bytes (and this size is known to the compiler). This is very important to the compiler, because if
some_variable is 4 bytes large, it knows the variable after
some_variable is stored 4 bytes later, which means it can hardcode that four in the compiled program. You can only store a variable on the stack if it is sized.
Now, how many bytes is a string? Well it depends on the length. “abc” is three bytes, while “hello world” is 11. So
str is not
Sized, which means you cannot put it on the stack. Luckily a reference
&str is always the same number of bytes (usually 4 or 8 depending on the computer). So storing a reference on the stack is fine.
When you type
let s = "Hello world";
the compiler will place the bytes
l, … somewhere in the executable, and in your function it will hardcode a reference to that location. This is why
s has the type
&str. You cannot put a
str in a variable at all, because variables are stored on the stack.
The situation is the same as
[T] is just some number of
Ts after each other, thus having variable length, while
&[T] is a pointer (of 4 or 8 bytes) that points to somewhere with the
Ts. Do note that there is an
[T; n] type, where you hardcode the number of elements. As an example, a
[i32; 8] has a known size and can be stored on the stack.
let a: [i32; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
However, you will not be able to resize a
[i32; 8], because the
8 is part of the type. In Hyeonu’s example you can see that you could store a string in a
[u8; 10], although you should note this means you can only have strings of length 10, while a
&str can point to a string of any length.