Skip to content

Commit ab3cb8c

Browse files
committed
TRPL: ownership, borrowing, and lifetimes
Also, as @huonw guessed, move semantics really _does_ make more sense as a sub-chapter of ownership.
1 parent f191f92 commit ab3cb8c

File tree

5 files changed

+740
-567
lines changed

5 files changed

+740
-567
lines changed

src/doc/trpl/SUMMARY.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
* [References and Borrowing](references-and-borrowing.md)
2727
* [Lifetimes](lifetimes.md)
2828
* [Mutability](mutability.md)
29-
* [Move semantics](move-semantics.md)
3029
* [Enums](enums.md)
3130
* [Match](match.md)
3231
* [Structs](structs.md)

src/doc/trpl/lifetimes.md

Lines changed: 295 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,297 @@
11
% Lifetimes
22

3-
Coming Soon! Until then, check out the [ownership](ownership.html) chapter.
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:
7+
8+
* [ownership][ownership], ownership, the key concept
9+
* [borrowing][borrowing], and their associated feature ‘references’
10+
* lifetimes, which you’re reading now
11+
12+
These three chapters are related, and in order. You’ll need all three to fully
13+
understand the ownership system.
14+
15+
[ownership]: ownership.html
16+
[borrowing]: references-and-borrowing.html
17+
18+
# Meta
19+
20+
Before we get to the details, two important notes about the ownership system.
21+
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
27+
features.
28+
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.
38+
39+
With that in mind, let’s learn about lifetimes.
40+
41+
# Lifetimes
42+
43+
Lending out a reference to a resource that someone else owns can be
44+
complicated, however. For example, imagine this set of operations:
45+
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
49+
your reference.
50+
- You decide to use the resource.
51+
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.
54+
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.
58+
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:
61+
62+
```rust
63+
// implicit
64+
fn foo(x: &i32) {
65+
}
66+
67+
// explicit
68+
fn bar<'a>(x: &'a i32) {
69+
}
70+
```
71+
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:
75+
76+
```rust,ignore
77+
fn bar<'a>(...)
78+
```
79+
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:
82+
83+
```rust,ignore
84+
fn bar<'a, 'b>(...)
85+
```
86+
87+
Then in our parameter list, we use the lifetimes we’ve named:
88+
89+
```rust,ignore
90+
...(x: &'a i32)
91+
```
92+
93+
If we wanted an `&mut` reference, we’d do this:
94+
95+
```rust,ignore
96+
...(x: &'a mut i32)
97+
```
98+
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`’.
103+
104+
You’ll also need explicit lifetimes when working with [`struct`][structs]s:
105+
106+
```rust
107+
struct Foo<'a> {
108+
x: &'a i32,
109+
}
110+
111+
fn main() {
112+
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
113+
let f = Foo { x: y };
114+
115+
println!("{}", f.x);
116+
}
117+
```
118+
119+
[struct]: structs.html
120+
121+
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
122+
123+
```rust
124+
struct Foo<'a> {
125+
# x: &'a i32,
126+
# }
127+
```
128+
129+
declares a lifetime, and
130+
131+
```rust
132+
# struct Foo<'a> {
133+
x: &'a i32,
134+
# }
135+
```
136+
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.
139+
140+
## Thinking in scopes
141+
142+
A way to think about lifetimes is to visualize the scope that a reference is
143+
valid for. For example:
144+
145+
```rust
146+
fn main() {
147+
let y = &5; // -+ y goes into scope
148+
// |
149+
// stuff // |
150+
// |
151+
} // -+ y goes out of scope
152+
```
153+
154+
Adding in our `Foo`:
155+
156+
```rust
157+
struct Foo<'a> {
158+
x: &'a i32,
159+
}
160+
161+
fn main() {
162+
let y = &5; // -+ y goes into scope
163+
let f = Foo { x: y }; // -+ f goes into scope
164+
// stuff // |
165+
// |
166+
} // -+ f and y go out of scope
167+
```
168+
169+
Our `f` lives within the scope of `y`, so everything works. What if it didn’t?
170+
This code won’t work:
171+
172+
```rust,ignore
173+
struct Foo<'a> {
174+
x: &'a i32,
175+
}
176+
177+
fn main() {
178+
let x; // -+ x goes into scope
179+
// |
180+
{ // |
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
185+
// |
186+
println!("{}", x); // |
187+
} // -+ x goes out of scope
188+
```
189+
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.
193+
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.
196+
197+
## 'static
198+
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:
202+
203+
```rust
204+
let x: &'static str = "Hello, world.";
205+
```
206+
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
209+
example are globals:
210+
211+
```rust
212+
static FOO: i32 = 5;
213+
let x: &'static i32 = &FOO;
214+
```
215+
216+
This adds an `i32` to the data segment of the binary, and `x` is a reference
217+
to it.
218+
219+
## Lifetime Elision
220+
221+
Rust supports powerful local type inference in function bodies, but it’s
222+
forbidden in item signatures to allow reasoning about the types just based in
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.
230+
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:
235+
236+
```rust,ignore
237+
fn foo<'a>(bar: &'a str)
238+
```
239+
240+
This one has an output lifetime:
241+
242+
```rust,ignore
243+
fn foo<'a>() -> &'a str
244+
```
245+
246+
This one has a lifetime in both positions:
247+
248+
```rust,ignore
249+
fn foo<'a>(bar: &'a str) -> &'a str
250+
```
251+
252+
Here are the three rules:
253+
254+
* Each elided lifetime in a function’s arguments becomes a distinct lifetime
255+
parameter.
256+
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.
259+
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.
262+
263+
Otherwise, it is an error to elide an output lifetime.
264+
265+
### Examples
266+
267+
Here are some examples of functions with elided lifetimes. We’ve paired each
268+
example of an elided lifetime with its expanded form.
269+
270+
```rust,ignore
271+
fn print(s: &str); // elided
272+
fn print<'a>(s: &'a str); // expanded
273+
274+
fn debug(lvl: u32, s: &str); // elided
275+
fn debug<'a>(lvl: u32, s: &'a str); // expanded
276+
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.
280+
281+
fn substr(s: &str, until: u32) -> &str; // elided
282+
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
283+
284+
fn get_str() -> &str; // ILLEGAL, no inputs
285+
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
288+
289+
fn get_mut(&mut self) -> &mut T; // elided
290+
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
291+
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
294+
295+
fn new(buf: &mut [u8]) -> BufWriter; // elided
296+
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
297+
```

0 commit comments

Comments
 (0)