3 This guide is one of three presenting Rust’s ownership system. This is one of
4 Rust’s most unique and compelling features, with which Rust developers should
5 become quite acquainted. Ownership is how Rust achieves its largest goal,
6 memory safety. There are a few distinct concepts, each with its own chapter:
8 * [ownership][ownership], the key concept
9 * [borrowing][borrowing], and their associated feature ‘references’
10 * lifetimes, which you’re reading now
12 These three chapters are related, and in order. You’ll need all three to fully
13 understand the ownership system.
15 [ownership]: ownership.html
16 [borrowing]: references-and-borrowing.html
20 Before we get to the details, two important notes about the ownership system.
22 Rust has a focus on safety and speed. It accomplishes these goals through many
23 ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little
24 as possible in order to make them work. The ownership system is a prime example
25 of a zero-cost abstraction. All of the analysis we’ll talk about in this guide
26 is _done at compile time_. You do not pay any run-time cost for any of these
29 However, this system does have a certain cost: learning curve. Many new users
30 to Rust experience something we like to call ‘fighting with the borrow
31 checker’, where the Rust compiler refuses to compile a program that the author
32 thinks is valid. This often happens because the programmer’s mental model of
33 how ownership should work doesn’t match the actual rules that Rust implements.
34 You probably will experience similar things at first. There is good news,
35 however: more experienced Rust developers report that once they work with the
36 rules of the ownership system for a period of time, they fight the borrow
37 checker less and less.
39 With that in mind, let’s learn about lifetimes.
43 Lending out a reference to a resource that someone else owns can be
44 complicated. For example, imagine this set of operations:
46 - I acquire a handle to some kind of resource.
47 - I lend you a reference to the resource.
48 - I decide I’m done with the resource, and deallocate it, while you still have
50 - You decide to use the resource.
52 Uh oh! Your reference is pointing to an invalid resource. This is called a
53 dangling pointer or ‘use after free’, when the resource is memory.
55 To fix this, we have to make sure that step four never happens after step
56 three. The ownership system in Rust does this through a concept called
57 lifetimes, which describe the scope that a reference is valid for.
59 When we have a function that takes a reference by argument, we can be implicit
60 or explicit about the lifetime of the reference:
68 fn bar<'a>(x: &'a i32) {
72 The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime
73 associated with it, but the compiler lets you elide them in common cases.
74 Before we get to that, though, let’s break the explicit example down:
80 This part declares our lifetimes. This says that `bar` has one lifetime, `'a`.
81 If we had two reference parameters, it would look like this:
87 Then in our parameter list, we use the lifetimes we’ve named:
93 If we wanted an `&mut` reference, we’d do this:
99 If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s just that
100 the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut
101 i32` as ‘a mutable reference to an i32’ and `&'a mut i32` as ‘a mutable
102 reference to an `i32` with the lifetime `'a`’.
106 You’ll also need explicit lifetimes when working with [`struct`][structs]s:
114 let y = &5; // this is the same as `let _y = 5; let y = &_y;`
115 let f = Foo { x: y };
121 [structs]: structs.html
123 As you can see, `struct`s can also have lifetimes. In a similar way to functions,
131 declares a lifetime, and
139 uses it. So why do we need a lifetime here? We need to ensure that any reference
140 to a `Foo` cannot outlive the reference to an `i32` it contains.
144 Let’s implement a method on `Foo`:
152 fn x(&self) -> &'a i32 { self.x }
156 let y = &5; // this is the same as `let _y = 5; let y = &_y;`
157 let f = Foo { x: y };
159 println!("x is: {}", f.x());
163 As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat
164 `'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>`
167 ## Multiple lifetimes
169 If you have multiple references, you can use the same lifetime multiple times:
172 fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str {
177 This says that `x` and `y` both are alive for the same scope, and that the
178 return value is also alive for that scope. If you wanted `x` and `y` to have
179 different lifetimes, you can use multiple lifetime parameters:
182 fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
187 In this example, `x` and `y` have different valid scopes, but the return value
188 has the same lifetime as `x`.
190 ## Thinking in scopes
192 A way to think about lifetimes is to visualize the scope that a reference is
193 valid for. For example:
197 let y = &5; // -+ y goes into scope
201 } // -+ y goes out of scope
212 let y = &5; // -+ y goes into scope
213 let f = Foo { x: y }; // -+ f goes into scope
216 } // -+ f and y go out of scope
219 Our `f` lives within the scope of `y`, so everything works. What if it didn’t?
220 This code won’t work:
228 let x; // -+ x goes into scope
231 let y = &5; // ---+ y goes into scope
232 let f = Foo { x: y }; // ---+ f goes into scope
233 x = &f.x; // | | error here
234 } // ---+ f and y go out of scope
236 println!("{}", x); // |
237 } // -+ x goes out of scope
240 Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
241 of `x`. But when we do `x = &f.x`, we make `x` a reference to something that’s
242 about to go out of scope.
244 Named lifetimes are a way of giving these scopes a name. Giving something a
245 name is the first step towards being able to talk about it.
249 The lifetime named ‘static’ is a special lifetime. It signals that something
250 has the lifetime of the entire program. Most Rust programmers first come across
251 `'static` when dealing with strings:
254 let x: &'static str = "Hello, world.";
257 String literals have the type `&'static str` because the reference is always
258 alive: they are baked into the data segment of the final binary. Another
263 let x: &'static i32 = &FOO;
266 This adds an `i32` to the data segment of the binary, and `x` is a reference
271 Rust supports powerful local type inference in function bodies, but it’s
272 forbidden in item signatures to allow reasoning about the types based on
273 the item signature alone. However, for ergonomic reasons a very restricted
274 secondary inference algorithm called “lifetime elision” applies in function
275 signatures. It infers only based on the signature components themselves and not
276 based on the body of the function, only infers lifetime parameters, and does
277 this with only three easily memorizable and unambiguous rules. This makes
278 lifetime elision a shorthand for writing an item signature, while not hiding
279 away the actual types involved as full local inference would if applied to it.
281 When talking about lifetime elision, we use the term *input lifetime* and
282 *output lifetime*. An *input lifetime* is a lifetime associated with a parameter
283 of a function, and an *output lifetime* is a lifetime associated with the return
284 value of a function. For example, this function has an input lifetime:
287 fn foo<'a>(bar: &'a str)
290 This one has an output lifetime:
293 fn foo<'a>() -> &'a str
296 This one has a lifetime in both positions:
299 fn foo<'a>(bar: &'a str) -> &'a str
302 Here are the three rules:
304 * Each elided lifetime in a function’s arguments becomes a distinct lifetime
307 * If there is exactly one input lifetime, elided or not, that lifetime is
308 assigned to all elided lifetimes in the return values of that function.
310 * If there are multiple input lifetimes, but one of them is `&self` or `&mut
311 self`, the lifetime of `self` is assigned to all elided output lifetimes.
313 Otherwise, it is an error to elide an output lifetime.
317 Here are some examples of functions with elided lifetimes. We’ve paired each
318 example of an elided lifetime with its expanded form.
321 fn print(s: &str); // elided
322 fn print<'a>(s: &'a str); // expanded
324 fn debug(lvl: u32, s: &str); // elided
325 fn debug<'a>(lvl: u32, s: &'a str); // expanded
327 // In the preceding example, `lvl` doesn’t need a lifetime because it’s not a
328 // reference (`&`). Only things relating to references (such as a `struct`
329 // which contains a reference) need lifetimes.
331 fn substr(s: &str, until: u32) -> &str; // elided
332 fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
334 fn get_str() -> &str; // ILLEGAL, no inputs
336 fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
337 fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous
339 fn get_mut(&mut self) -> &mut T; // elided
340 fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
342 fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
343 fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
345 fn new(buf: &mut [u8]) -> BufWriter; // elided
346 fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded