]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/lifetime-mismatch.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / nomicon / src / lifetime-mismatch.md
1 # Limits of Lifetimes
2
3 Given the following code:
4
5 ```rust,edition2018,compile_fail
6 #[derive(Debug)]
7 struct Foo;
8
9 impl Foo {
10 fn mutate_and_share(&mut self) -> &Self { &*self }
11 fn share(&self) {}
12 }
13
14 fn main() {
15 let mut foo = Foo;
16 let loan = foo.mutate_and_share();
17 foo.share();
18 println!("{:?}", loan);
19 }
20 ```
21
22 One might expect it to compile. We call `mutate_and_share`, which mutably
23 borrows `foo` temporarily, but then returns only a shared reference. Therefore
24 we would expect `foo.share()` to succeed as `foo` shouldn't be mutably borrowed.
25
26 However when we try to compile it:
27
28 ```text
29 error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
30 --> src/main.rs:12:5
31 |
32 11 | let loan = foo.mutate_and_share();
33 | --- mutable borrow occurs here
34 12 | foo.share();
35 | ^^^ immutable borrow occurs here
36 13 | println!("{:?}", loan);
37 ```
38
39 What happened? Well, we got the exact same reasoning as we did for
40 [Example 2 in the previous section][ex2]. We desugar the program and we get
41 the following:
42
43 ```rust,ignore
44 struct Foo;
45
46 impl Foo {
47 fn mutate_and_share<'a>(&'a mut self) -> &'a Self { &'a *self }
48 fn share<'a>(&'a self) {}
49 }
50
51 fn main() {
52 'b: {
53 let mut foo: Foo = Foo;
54 'c: {
55 let loan: &'c Foo = Foo::mutate_and_share::<'c>(&'c mut foo);
56 'd: {
57 Foo::share::<'d>(&'d foo);
58 }
59 println!("{:?}", loan);
60 }
61 }
62 }
63 ```
64
65 The lifetime system is forced to extend the `&mut foo` to have lifetime `'c`,
66 due to the lifetime of `loan` and `mutate_and_share`'s signature. Then when we
67 try to call `share`, and it sees we're trying to alias that `&'c mut foo` and
68 blows up in our face!
69
70 This program is clearly correct according to the reference semantics we actually
71 care about, but the lifetime system is too coarse-grained to handle that.
72
73
74
75 # Improperly reduced borrows
76
77 The following code fails to compile, because Rust doesn't understand that the borrow
78 is no longer needed and conservatively falls back to using a whole scope for it.
79 This will eventually get fixed.
80
81 ```rust,edition2018,compile_fail
82 # use std::collections::HashMap;
83 # use std::hash::Hash;
84 fn get_default<'m, K, V>(map: &'m mut HashMap<K, V>, key: K) -> &'m mut V
85 where
86 K: Clone + Eq + Hash,
87 V: Default,
88 {
89 match map.get_mut(&key) {
90 Some(value) => value,
91 None => {
92 map.insert(key.clone(), V::default());
93 map.get_mut(&key).unwrap()
94 }
95 }
96 }
97 ```
98
99 Because of the lifetime restrictions imposed, `&mut map`'s lifetime
100 overlaps other mutable borrows, resulting in a compile error:
101
102 ```text
103 error[E0499]: cannot borrow `*map` as mutable more than once at a time
104 --> src/main.rs:12:13
105 |
106 4 | fn get_default<'m, K, V>(map: &'m mut HashMap<K, V>, key: K) -> &'m mut V
107 | -- lifetime `'m` defined here
108 ...
109 9 | match map.get_mut(&key) {
110 | - --- first mutable borrow occurs here
111 | _____|
112 | |
113 10 | | Some(value) => value,
114 11 | | None => {
115 12 | | map.insert(key.clone(), V::default());
116 | | ^^^ second mutable borrow occurs here
117 13 | | map.get_mut(&key).unwrap()
118 14 | | }
119 15 | | }
120 | |_____- returning this value requires that `*map` is borrowed for `'m`
121 ```
122
123
124 [ex2]: lifetimes.html#example-aliasing-a-mutable-reference