]>
Commit | Line | Data |
---|---|---|
3dfed10e | 1 | A temporary value is being dropped while a borrow is still in active use. |
60c5eb7d XL |
2 | |
3 | Erroneous code example: | |
4 | ||
5 | ```compile_fail,E0716 | |
6 | fn foo() -> i32 { 22 } | |
7 | fn bar(x: &i32) -> &i32 { x } | |
8 | let p = bar(&foo()); | |
9 | // ------ creates a temporary | |
10 | let q = *p; | |
11 | ``` | |
12 | ||
3dfed10e XL |
13 | Here, the expression `&foo()` is borrowing the expression `foo()`. As `foo()` is |
14 | a call to a function, and not the name of a variable, this creates a | |
15 | **temporary** -- that temporary stores the return value from `foo()` so that it | |
16 | can be borrowed. You could imagine that `let p = bar(&foo());` is equivalent to | |
136023e0 XL |
17 | the following, which uses an explicit temporary variable. |
18 | ||
19 | Erroneous code example: | |
60c5eb7d XL |
20 | |
21 | ```compile_fail,E0597 | |
22 | # fn foo() -> i32 { 22 } | |
23 | # fn bar(x: &i32) -> &i32 { x } | |
24 | let p = { | |
25 | let tmp = foo(); // the temporary | |
136023e0 | 26 | bar(&tmp) // error: `tmp` does not live long enough |
60c5eb7d XL |
27 | }; // <-- tmp is freed as we exit this block |
28 | let q = p; | |
29 | ``` | |
30 | ||
3dfed10e XL |
31 | Whenever a temporary is created, it is automatically dropped (freed) according |
32 | to fixed rules. Ordinarily, the temporary is dropped at the end of the enclosing | |
33 | statement -- in this case, after the `let`. This is illustrated in the example | |
34 | above by showing that `tmp` would be freed as we exit the block. | |
60c5eb7d | 35 | |
3dfed10e XL |
36 | To fix this problem, you need to create a local variable to store the value in |
37 | rather than relying on a temporary. For example, you might change the original | |
38 | program to the following: | |
60c5eb7d XL |
39 | |
40 | ``` | |
41 | fn foo() -> i32 { 22 } | |
42 | fn bar(x: &i32) -> &i32 { x } | |
43 | let value = foo(); // dropped at the end of the enclosing block | |
44 | let p = bar(&value); | |
45 | let q = *p; | |
46 | ``` | |
47 | ||
3dfed10e XL |
48 | By introducing the explicit `let value`, we allocate storage that will last |
49 | until the end of the enclosing block (when `value` goes out of scope). When we | |
50 | borrow `&value`, we are borrowing a local variable that already exists, and | |
51 | hence no temporary is created. | |
60c5eb7d | 52 | |
3dfed10e XL |
53 | Temporaries are not always dropped at the end of the enclosing statement. In |
54 | simple cases where the `&` expression is immediately stored into a variable, the | |
55 | compiler will automatically extend the lifetime of the temporary until the end | |
56 | of the enclosing block. Therefore, an alternative way to fix the original | |
60c5eb7d XL |
57 | program is to write `let tmp = &foo()` and not `let tmp = foo()`: |
58 | ||
59 | ``` | |
60 | fn foo() -> i32 { 22 } | |
61 | fn bar(x: &i32) -> &i32 { x } | |
62 | let value = &foo(); | |
63 | let p = bar(value); | |
64 | let q = *p; | |
65 | ``` | |
66 | ||
3dfed10e XL |
67 | Here, we are still borrowing `foo()`, but as the borrow is assigned directly |
68 | into a variable, the temporary will not be dropped until the end of the | |
69 | enclosing block. Similar rules apply when temporaries are stored into aggregate | |
70 | structures like a tuple or struct: | |
60c5eb7d XL |
71 | |
72 | ``` | |
73 | // Here, two temporaries are created, but | |
74 | // as they are stored directly into `value`, | |
75 | // they are not dropped until the end of the | |
76 | // enclosing block. | |
77 | fn foo() -> i32 { 22 } | |
78 | let value = (&foo(), &foo()); | |
79 | ``` |