Quick Question: &'static str

Hi guys, i want to know what this statement &'static str does and mean?
I saw this in the rust tutorial on the rust doc website.
Are the better way to write the same statement?
Here is an example use case:

  trait Animal {
    // Static method signature; `Self` refers to the implementor type.
    fn new(name: &'static str) -> Self;

    // Instance method signatures; these will return a string.
    fn name(&self) -> &'static str;
    fn noise(&self) -> &'static str;

    // Traits can provide default method definitions.
    fn talk(&self) {
        println!("{} says {}", self.name(), self.noise());
    }
}
5 Likes

This is both very easy and not-so-easy to answer, because it steps on some advanced territory if you look closely. I'll try to leave that out.

So, first, it's not a "statement", it's a type, namely the type of variables (e.g. of the variable name, or of the unnamed return values of your functions). The fact that there's a &, but the keyword mut is missing, tells you that it is a so-called "shared reference". If you know C, it's a bit like a pointer, but here Rust knows it's shared, so it's not unique, so you're guaranteed that nobody changes or removes the thing it's pointing to while you have your reference. That's a pretty strong guarantee and lets you read from it safely at any point.

The str part tells you what the reference is pointing to. That's the "a bit advanced" part, so let's just stay on the surface. It means that it points to a sequence of bytes which are valid UTF-8. That is, it's one of the string types of Rust, and you can do "stringly" things with it, e.g. print it. You can't modify it (because you have a shared reference, see above), but you can look at it's chars, compare it with other strings and such.

Finally, if you remember your C, pointers might be invalid, because the thing they're pointing to has been deallocated. That's not true for references in Rust, they are always valid, guaranteed. To uphold that guarantee, Rust needs a notation of "how long is this reference valid?". The 'static part means that the reference is valid for the whole program. Most of the time this means that the byte sequence lives in the static memory of the binary, and has been validated to be UTF-8 at compile time (but that's not strictly always true).

13 Likes

First of all, &'static str is a type which consists of 3 parts - &, 'static, str.

& means this type is a reference, borrowed from a value owned by someone else. Every references has associated its lifetime and the Rust compiler proves that the usage of the reference never exceed its lifetime. Safe Rust cannot touches dangling reference even by accident.

'a is a lifetime notation named a, and 'static is a special one which represents the lifetime of the process itself. It ends when the process terminates so it can be practically considered endless. &'static means a reference that cannot be dangling.

str is a type which represents a sequence of bytes which also is valid UTF-8 sequence. It's size cannot be determined statically as there isn't single "length" for every possible text data. In Rust we call such types DST(Dynamically Sized Type) and they cannot be placed on the stack without some indirection types like Box<T>, &T etc.

As a conclusion, &'static str is a reference to the UTF-8 encoded variable length of byte sequence, which is valid for the entire lifetime of the process. But how can we obtain such type? Normally it's from the string literals, which are embeded directly on the executable binary(like .rodata section of the elf file) and loaded to the read-only section of the memory by the OS before execution.

7 Likes

Not entirely accurate description, but most practical is that 'static means either:

  1. Leaked memory.
  2. References are not allowed.

String literals and immutable globals are not freed until the end of your program, so they're in a way a leaked memory. There's also Box::leak that does exactly what it says and produces a 'static reference. There only few situations in which it's OK to not free memory, so you will rarely find such uses of 'static in real programs.

In generic context some code adds + 'static requirement, which is a indirect way of saying temporary references are not allowed. Static references are a special and mostly useless case (leaked mem), and no other kind of borrows can meet that special requirement. Therefore, when the compiler says "'static is required", then it's trying to say that normal (i.e. temporary) references just can't work there.

4 Likes

While I understand where you're coming from, I'm not sure I entirely agree with calling it leaked memory. Yes it looks a bit like leaked memory if you look at it funny, especially the fact that it isn't cleaned up until program termination.
However, it also has an important difference: the 'static data is (presumably) in actual use, for quite possibly the entire life of the program.

Either that or it's the result of some compile time calculation in a proc macro, which is a technique I've used once or twice so far. The resulting objects aren't huge in my case, and they're used all the time while the generated library is used.

2 Likes

That's why I've added a disclaimer that it's not entirely accurate.

But the key point is that when rustc says that a &'static reference is required, then it's very unlikely that taking this advice literally is going to produce something that is both useful (i.e. more than using it with a string literal on rust playground to prove it compiles) and doesn't leak memory.

Animal::new(Box::leak(name))

Thanks guys for this explanation.
I have properly understood the meaning.

Still on this matter, i still need some clarifications.
When i was compiling and assign a struct property with type: str, i got this error from compiler:

the size for values of type str cannot be known at compilation time

But when i changed it to & 'static str the error stopped.

Why is that?

The size of a str is the number of bytes in it, e.g. "hello" as a str has the size 5, while "foo" would have the size 3. Since the size depends on the value, you cannot store it in a variable.

On the other hand, the type &str is a reference to a str stored somewhere else. It's just an integer describing a memory location along with another integer describing it's length. Since integers are always the same size, the size is known at compile time.

Of course, when using &str, the actual string is stored somewhere else. In this case the string is stored somewhere in your executable file, which is loaded into memory by the OS when you run it, and the memory location is hard-coded in the executable by the compiler.

The 'static marker just means that the reference is valid for the full lifetime of the program.

Thanks @alice that means if i have to use a str type, i must initialize it at that point?
Or what do you suggest?

I'm not quite sure what you mean. If you need to pass a function a string, you can give it a &str. You can get a value of type &str by using a string literal (e.g. "foo") or by borrowing a value of type String.

What i meant is this:

struct Dog{
    name: "Bingo" //that is if i have to initialize it at this point or better still reference it &str
}

Rather than doing:

struct Dog{
    name: str
}

You probably want this:

struct Dog {
    name: String,
}

and when creating a value of this type:

Dog {
    name: String::from("Bingo"),
}
1 Like

Thanks @alice thats exactly what i needed to know.
Your explanation is clear and concise.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.