3 This guide is three 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 1. I acquire a handle to some kind of resource.
47 2. I lend you a reference to the resource.
48 3. I decide I’m done with the resource, and deallocate it, while you still have
50 4. 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 (i.e. omit, see
74 ["Lifetime Elision"][lifetime-elision] below) them in common cases.
75 Before we get to that, though, let’s break the explicit example down:
77 [lifetime-elision]: #lifetime-elision
83 We previously talked a little about [function syntax][functions], but we didn’t
84 discuss the `<>`s after a function’s name. A function can have ‘generic
85 parameters’ between the `<>`s, of which lifetimes are one kind. We’ll discuss
86 other kinds of generics [later in the book][generics], but for now, let’s
87 just focus on the lifetimes aspect.
89 [functions]: functions.html
90 [generics]: generics.html
92 We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
93 `'a`. If we had two reference parameters, it would look like this:
100 Then in our parameter list, we use the lifetimes we’ve named:
106 If we wanted an `&mut` reference, we’d do this:
112 If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s just that
113 the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut
114 i32` as ‘a mutable reference to an `i32`’ and `&'a mut i32` as ‘a mutable
115 reference to an `i32` with the lifetime `'a`’.
119 You’ll also need explicit lifetimes when working with [`struct`][structs]s that
128 let y = &5; // this is the same as `let _y = 5; let y = &_y;`
129 let f = Foo { x: y };
135 [structs]: structs.html
137 As you can see, `struct`s can also have lifetimes. In a similar way to functions,
145 declares a lifetime, and
153 uses it. So why do we need a lifetime here? We need to ensure that any reference
154 to a `Foo` cannot outlive the reference to an `i32` it contains.
158 Let’s implement a method on `Foo`:
166 fn x(&self) -> &'a i32 { self.x }
170 let y = &5; // this is the same as `let _y = 5; let y = &_y;`
171 let f = Foo { x: y };
173 println!("x is: {}", f.x());
177 As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat
178 `'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>`
181 ## Multiple lifetimes
183 If you have multiple references, you can use the same lifetime multiple times:
186 fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str {
191 This says that `x` and `y` both are alive for the same scope, and that the
192 return value is also alive for that scope. If you wanted `x` and `y` to have
193 different lifetimes, you can use multiple lifetime parameters:
196 fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
201 In this example, `x` and `y` have different valid scopes, but the return value
202 has the same lifetime as `x`.
204 ## Thinking in scopes
206 A way to think about lifetimes is to visualize the scope that a reference is
207 valid for. For example:
211 let y = &5; // -+ y goes into scope
215 } // -+ y goes out of scope
226 let y = &5; // -+ y goes into scope
227 let f = Foo { x: y }; // -+ f goes into scope
230 } // -+ f and y go out of scope
233 Our `f` lives within the scope of `y`, so everything works. What if it didn’t?
234 This code won’t work:
242 let x; // -+ x goes into scope
245 let y = &5; // ---+ y goes into scope
246 let f = Foo { x: y }; // ---+ f goes into scope
247 x = &f.x; // | | error here
248 } // ---+ f and y go out of scope
250 println!("{}", x); // |
251 } // -+ x goes out of scope
254 Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
255 of `x`. But when we do `x = &f.x`, we make `x` a reference to something that’s
256 about to go out of scope.
258 Named lifetimes are a way of giving these scopes a name. Giving something a
259 name is the first step towards being able to talk about it.
263 The lifetime named ‘static’ is a special lifetime. It signals that something
264 has the lifetime of the entire program. Most Rust programmers first come across
265 `'static` when dealing with strings:
268 let x: &'static str = "Hello, world.";
271 String literals have the type `&'static str` because the reference is always
272 alive: they are baked into the data segment of the final binary. Another
277 let x: &'static i32 = &FOO;
280 This adds an `i32` to the data segment of the binary, and `x` is a reference
285 Rust supports powerful local type inference in function bodies, but it’s
286 forbidden in item signatures to allow reasoning about the types based on
287 the item signature alone. However, for ergonomic reasons a very restricted
288 secondary inference algorithm called “lifetime elision” applies in function
289 signatures. It infers only based on the signature components themselves and not
290 based on the body of the function, only infers lifetime parameters, and does
291 this with only three easily memorizable and unambiguous rules. This makes
292 lifetime elision a shorthand for writing an item signature, while not hiding
293 away the actual types involved as full local inference would if applied to it.
295 When talking about lifetime elision, we use the term *input lifetime* and
296 *output lifetime*. An *input lifetime* is a lifetime associated with a parameter
297 of a function, and an *output lifetime* is a lifetime associated with the return
298 value of a function. For example, this function has an input lifetime:
301 fn foo<'a>(bar: &'a str)
304 This one has an output lifetime:
307 fn foo<'a>() -> &'a str
310 This one has a lifetime in both positions:
313 fn foo<'a>(bar: &'a str) -> &'a str
316 Here are the three rules:
318 * Each elided lifetime in a function’s arguments becomes a distinct lifetime
321 * If there is exactly one input lifetime, elided or not, that lifetime is
322 assigned to all elided lifetimes in the return values of that function.
324 * If there are multiple input lifetimes, but one of them is `&self` or `&mut
325 self`, the lifetime of `self` is assigned to all elided output lifetimes.
327 Otherwise, it is an error to elide an output lifetime.
331 Here are some examples of functions with elided lifetimes. We’ve paired each
332 example of an elided lifetime with its expanded form.
335 fn print(s: &str); // elided
336 fn print<'a>(s: &'a str); // expanded
338 fn debug(lvl: u32, s: &str); // elided
339 fn debug<'a>(lvl: u32, s: &'a str); // expanded
341 // In the preceding example, `lvl` doesn’t need a lifetime because it’s not a
342 // reference (`&`). Only things relating to references (such as a `struct`
343 // which contains a reference) need lifetimes.
345 fn substr(s: &str, until: u32) -> &str; // elided
346 fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
348 fn get_str() -> &str; // ILLEGAL, no inputs
350 fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
351 fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous
353 fn get_mut(&mut self) -> &mut T; // elided
354 fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
356 fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided
357 fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded
359 fn new(buf: &mut [u8]) -> BufWriter; // elided
360 fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded