DEV Community

Cover image for Lifetimes in Rust explained
Francesco Ciulla
Francesco Ciulla

Posted on

Lifetimes in Rust explained

I want to discuss a fundamental concept you must grasp to master the Rust programming language: “Lifetimes.”

Usually, when we learn about a programming language, we reference other languages, like “it works like in JavaScript,” “it’s similar to Python,” and so on.

We can’t make this analogy in this case because “Lifetimes” are peculiar to the Rust programming language.

Lifetimes in Rust ensure that references are valid as long as they are used, preventing common bugs like dangling pointers and use-after-free errors.

This article explores lifetimes, their significance, and how to work with them through examples.

If you prefer a video version

So what are lifetimes?

In short, Lifetimes are a form of generic parameter that describes the scope for which a reference is valid. The Rust compiler uses lifetimes to check that references do not outlive the data they point to, ensuring memory safety.

In Rust, every reference has a lifetime (even though you don't always see it in the code). The compiler infers lifetimes in many cases, but sometimes you need to specify them explicitly, especially in function signatures and struct definitions.

Basic Example:

Let’s see a basic example

Lifetimes in Rust

In this example, x is created inside an inner scope and is destroyed at the end of that scope.

The reference r points to x, but r is used outside the scope where x was valid. Rust's borrow checker will produce a compile-time error to prevent this situation.

Explicit Lifetimes in Function Signatures

Sometimes, you need to write functions that accept references and return references. To ensure the references are valid, you must specify the lifetimes explicitly.

Consider this function that returns the longer of two string slice:

Lifetimes in Rust

In the function longest, we declare a lifetime parameter 'a and use it to indicate that the references s1 and s2 must be valid for at least as long as the returned reference.

This ensures the returned reference does not outlive the data it points to.

Lifetimes in Structs

Lifetimes are also used in structs to ensure that references held by the struct do not outlive the struct itself.

Let’s see an example:

Lifetimes in Rust

In this example, the ImportantExcerpt struct references a part of a string. The lifetime 'a ensures that the reference part cannot outlive the ImportantExcerpt instance, thereby preventing invalid references.

Conclusion

Lifetimes in Rust are a powerful feature that guarantees memory safety by ensuring references are valid for as long as they are used.

While the compiler often infers lifetimes, understanding and specifying them explicitly when needed is important for writing robust Rust programs.

With these examples and explanations, you should have a good foundation to explore more complex scenarios involving lifetimes in Rust.

If you prefer a video version

Top comments (4)

Collapse
 
lexlohr profile image
Alex Lohr

I understood lifetimes like this: whenever something is not owned, the compiler needs to know how long to keep it alive and requires you to define what parts of your program depend on it so that it does not drop it as long as those are running.

Collapse
 
qwuik profile image
Mike • Edited

Compiler doesn't keep it alive. Compiler checks that this particular X has lifetime enough for all operations with that X, so there are no dead references and memory leak.

Collapse
 
francescoxx profile image
Francesco Ciulla

Thank you for the clarification, Mike. You're right—the compiler doesn't keep the reference alive but instead ensures that the lifetime of a reference is sufficient for all operations involving it. This prevents dead references and memory leaks by enforcing safe memory usage throughout the program. Thanks for pointing that out!

Collapse
 
francescoxx profile image
Francesco Ciulla

Thank you for sharing your understanding of lifetimes! You've captured the essence well. The compiler indeed needs to ensure that any references remain valid for as long as they are used, preventing premature deallocation. Defining lifetimes helps manage this, ensuring safe and predictable behavior in your program.

The only correction is that the compiler is not in charge of keeping it alive, but rather checking that