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`’.
104 You’ll also need explicit lifetimes when working with [`struct`][structs]s:
112 let y = &5; // this is the same as `let _y = 5; let y = &_y;`
113 let f = Foo { x: y };
119 [structs]: structs.html
121 As you can see, `struct`s can also have lifetimes. In a similar way to functions,
129 declares a lifetime, and
137 uses it. So why do we need a lifetime here? We need to ensure that any reference
138 to a `Foo` cannot outlive the reference to an `i32` it contains.
140 ## Thinking in scopes
142 A way to think about lifetimes is to visualize the scope that a reference is
143 valid for. For example:
147 let y = &5; // -+ y goes into scope
151 } // -+ y goes out of scope
162 let y = &5; // -+ y goes into scope
163 let f = Foo { x: y }; // -+ f goes into scope
166 } // -+ f and y go out of scope
169 Our `f` lives within the scope of `y`, so everything works. What if it didn’t?
170 This code won’t work:
178 let x; // -+ x goes into scope
181 let y = &5; // ---+ y goes into scope
182 let f = Foo { x: y }; // ---+ f goes into scope
183 x = &f.x; // | | error here
184 } // ---+ f and y go out of scope
186 println!("{}", x); // |
187 } // -+ x goes out of scope
190 Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
191 of `x`. But when we do `x = &f.x`, we make `x` a reference to something that’s
192 about to go out of scope.
194 Named lifetimes are a way of giving these scopes a name. Giving something a
195 name is the first step towards being able to talk about it.
199 The lifetime named ‘static’ is a special lifetime. It signals that something
200 has the lifetime of the entire program. Most Rust programmers first come across
201 `'static` when dealing with strings:
204 let x: &'static str = "Hello, world.";
207 String literals have the type `&'static str` because the reference is always
208 alive: they are baked into the data segment of the final binary. Another
213 let x: &'static i32 = &FOO;
216 This adds an `i32` to the data segment of the binary, and `x` is a reference
221 Rust supports powerful local type inference in function bodies, but it’s
222 forbidden in item signatures to allow reasoning about the types based on
223 the item signature alone. However, for ergonomic reasons a very restricted
224 secondary inference algorithm called “lifetime elision” applies in function
225 signatures. It infers only based on the signature components themselves and not
226 based on the body of the function, only infers lifetime parameters, and does
227 this with only three easily memorizable and unambiguous rules. This makes
228 lifetime elision a shorthand for writing an item signature, while not hiding
229 away the actual types involved as full local inference would if applied to it.
231 When talking about lifetime elision, we use the term *input lifetime* and
232 *output lifetime*. An *input lifetime* is a lifetime associated with a parameter
233 of a function, and an *output lifetime* is a lifetime associated with the return
234 value of a function. For example, this function has an input lifetime:
237 fn foo<'a>(bar: &'a str)
240 This one has an output lifetime:
243 fn foo<'a>() -> &'a str
246 This one has a lifetime in both positions:
249 fn foo<'a>(bar: &'a str) -> &'a str
252 Here are the three rules:
254 * Each elided lifetime in a function’s arguments becomes a distinct lifetime
257 * If there is exactly one input lifetime, elided or not, that lifetime is
258 assigned to all elided lifetimes in the return values of that function.
260 * If there are multiple input lifetimes, but one of them is `&self` or `&mut
261 self`, the lifetime of `self` is assigned to all elided output lifetimes.
263 Otherwise, it is an error to elide an output lifetime.
267 Here are some examples of functions with elided lifetimes. We’ve paired each
268 example of an elided lifetime with its expanded form.
271 fn print(s: &str); // elided
272 fn print<'a>(s: &'a str); // expanded
274 fn debug(lvl: u32, s: &str); // elided
275 fn debug<'a>(lvl: u32, s: &'a str); // expanded
277 // In the preceding example, `lvl` doesn’t need a lifetime because it’s not a
278 // reference (`&`). Only things relating to references (such as a `struct`
279 // which contains a reference) need lifetimes.
281 fn substr(s: &str, until: u32) -> &str; // elided
282 fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
284 fn get_str() -> &str; // ILLEGAL, no inputs
286 fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
287 fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear
289 fn get_mut(&mut self) -> &mut T; // elided
290 fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
292 fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
293 fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
295 fn new(buf: &mut [u8]) -> BufWriter; // elided
296 fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded