]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/lifetime-mismatch.md
New upstream version 1.38.0+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 This currently 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
100 [ex2]: lifetimes.html#example-aliasing-a-mutable-reference