Skip to content

Commit 21b4b9f

Browse files
committed
Copy/move lifetime elision document from other places
1 parent 1d791b5 commit 21b4b9f

File tree

5 files changed

+187
-106
lines changed

5 files changed

+187
-106
lines changed

Diff for: src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
- [Subtyping](subtyping.md)
6767
- [Type coercions](type-coercions.md)
6868
- [Destructors](destructors.md)
69+
- [Lifetime elision](lifetime-elision.md)
6970

7071
- [Special types and traits](special-types-and-traits.md)
7172

Diff for: src/items/constant-items.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ fn create_and_drop_zero_with_destructor() {
6161
```
6262

6363
[constant value]: expressions.html#constant-expressions
64-
[static lifetime elision]: items/static-items.html#static-lifetime-elision
64+
[static lifetime elision]: items/lifetime-elision.html#static-lifetime-elision
6565
[`Drop`]: special-types-and-traits.html#drop
6666
[IDENTIFIER]: identifiers.html
6767
[_Type_]: types.html

Diff for: src/items/static-items.md

-45
Original file line numberDiff line numberDiff line change
@@ -59,50 +59,6 @@ unsafe fn bump_levels_unsafe2() -> u32 {
5959
Mutable statics have the same restrictions as normal statics, except that the
6060
type does not have to implement the `Sync` trait.
6161

62-
## `'static` lifetime elision
63-
64-
Both constant and static declarations of reference types have *implicit*
65-
`'static` lifetimes unless an explicit lifetime is specified. As such, the
66-
constant declarations involving `'static` above may be written without the
67-
lifetimes. Returning to our previous example:
68-
69-
```rust
70-
const BIT1: u32 = 1 << 0;
71-
const BIT2: u32 = 1 << 1;
72-
73-
const BITS: [u32; 2] = [BIT1, BIT2];
74-
const STRING: &str = "bitstring";
75-
76-
struct BitsNStrings<'a> {
77-
mybits: [u32; 2],
78-
mystring: &'a str,
79-
}
80-
81-
const BITS_N_STRINGS: BitsNStrings = BitsNStrings {
82-
mybits: BITS,
83-
mystring: STRING,
84-
};
85-
```
86-
87-
Note that if the `static` or `const` items include function or closure
88-
references, which themselves include references, the compiler will first try
89-
the standard elision rules ([see discussion in the nomicon][elision-nomicon]).
90-
If it is unable to resolve the lifetimes by its usual rules, it will default to
91-
using the `'static` lifetime. By way of example:
92-
93-
```rust,ignore
94-
// Resolved as `fn<'a>(&'a str) -> &'a str`.
95-
const RESOLVED_SINGLE: fn(&str) -> &str = ..
96-
97-
// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`.
98-
const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..
99-
100-
// There is insufficient information to bound the return reference lifetime
101-
// relative to the argument lifetimes, so the signature is resolved as
102-
// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
103-
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
104-
```
105-
10662
## Using Statics or Consts
10763

10864
In can be confusing whether or not you should use a constant item or a static
@@ -118,4 +74,3 @@ following are true:
11874
[IDENTIFIER]: identifiers.html
11975
[_Type_]: types.html
12076
[_Expression_]: expressions.html
121-
[elision-nomicon]: ../nomicon/lifetime-elision.html

Diff for: src/lifetime-elision.md

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Lifetime elision
2+
3+
Rust has rules that allow lifetimes to be elided in various places where the
4+
compiler can infer a sensible default choice.
5+
6+
## Lifetime elision in functions
7+
8+
In order to make common patterns more ergonomic, Rust allows lifetimes to be
9+
*elided* in function signatures.
10+
11+
A *lifetime position* is anywhere you can write a lifetime in a type:
12+
13+
```rust,ignore
14+
&'a T
15+
&'a mut T
16+
T<'a>
17+
```
18+
19+
Lifetime positions can appear as either "input" or "output":
20+
21+
* For `fn` definitions, input refers to the types of the formal arguments
22+
in the `fn` definition, while output refers to
23+
result types. So `fn foo(s: &str) -> (&str, &str)` has elided one lifetime in
24+
input position and two lifetimes in output position.
25+
Note that the input positions of a `fn` method definition do not
26+
include the lifetimes that occur in the method's `impl` header
27+
(nor lifetimes that occur in the trait header, for a default method).
28+
29+
* In the future, it should be possible to elide `impl` headers in the same manner.
30+
31+
Elision rules are as follows:
32+
33+
* Each elided lifetime in input position becomes a distinct lifetime
34+
parameter.
35+
36+
* If there is exactly one input lifetime position (elided or not), that lifetime
37+
is assigned to *all* elided output lifetimes.
38+
39+
* If there are multiple input lifetime positions, but one of them is `&self` or
40+
`&mut self`, the lifetime of `self` is assigned to *all* elided output lifetimes.
41+
42+
* Otherwise, it is an error to elide an output lifetime.
43+
44+
Examples:
45+
46+
```rust,ignore
47+
fn print(s: &str); // elided
48+
fn print<'a>(s: &'a str); // expanded
49+
50+
fn debug(lvl: usize, s: &str); // elided
51+
fn debug<'a>(lvl: usize, s: &'a str); // expanded
52+
53+
fn substr(s: &str, until: usize) -> &str; // elided
54+
fn substr<'a>(s: &'a str, until: usize) -> &'a str; // expanded
55+
56+
fn get_str() -> &str; // ILLEGAL
57+
58+
fn frob(s: &str, t: &str) -> &str; // ILLEGAL
59+
60+
fn get_mut(&mut self) -> &mut T; // elided
61+
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
62+
63+
fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
64+
fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
65+
66+
fn new(buf: &mut [u8]) -> BufWriter; // elided
67+
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
68+
69+
```
70+
71+
## Defaults trait object lifetimes
72+
73+
The assumed lifetime of references held by a trait object is called its
74+
*default object lifetime bound*. These were defined in [RFC 599] and amended in
75+
[RFC 1156].
76+
77+
For traits that themselves have no lifetime parameters:
78+
* If there is a unique bound from the containing type then that is the default.
79+
* If there is more than one bound from the containing type then an explicit
80+
bound must be specified.
81+
* Otherwise the default bound is `'static`.
82+
83+
```rust,ignore
84+
// For the following trait...
85+
trait Foo { }
86+
87+
// These two are the same as Box<T> has no lifetime bound on T
88+
Box<Foo>
89+
Box<Foo + 'static>
90+
91+
// ...and so are these:
92+
impl Foo {}
93+
impl Foo + 'static {}
94+
95+
// ...so are these, because &'a T requires T: 'a
96+
&'a Foo
97+
&'a (Foo + 'a)
98+
99+
// std::cell::Ref<'a, T> also requires T: 'a, so these are the same
100+
std::cell::Ref<'a, Foo>
101+
std::cell::Ref<'a, Foo + 'a>
102+
103+
// This is an error:
104+
struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b>
105+
TwoBounds<'a, 'b, Foo> // Error: the lifetime bound for this object type cannot
106+
// be deduced from context
107+
108+
```
109+
110+
The `+ 'static` and `+ 'a` refer to the default bounds of those kinds of trait
111+
objects, and also to how you can directly override them. Note that the innermost
112+
object sets the bound, so `&'a Box<Foo>` is still `&'a Box<Foo + 'static>`.
113+
114+
For traits that have a single lifetime _bound_ of their own then, instead of
115+
infering 'static as the default bound, the bound on the trait is used instead
116+
117+
```rust,ignore
118+
// For the following trait...
119+
trait Bar<'a>: 'a { }
120+
121+
// ...these two are the same:
122+
Box<Bar<'a>>
123+
Box<Bar<'a> + 'a>
124+
125+
// ...and so are these:
126+
impl<'a> Foo<'a> {}
127+
impl<'a> Foo<'a> + 'a {}
128+
129+
// This is still an error:
130+
struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b>
131+
TwoBounds<'a, 'b, Foo<'c>>
132+
```
133+
134+
## `'static` lifetime elision
135+
136+
Both constant and static declarations of reference types have *implicit*
137+
`'static` lifetimes unless an explicit lifetime is specified. As such, the
138+
constant declarations involving `'static` above may be written without the
139+
lifetimes. Returning to our previous example:
140+
141+
```rust
142+
const BIT1: u32 = 1 << 0;
143+
const BIT2: u32 = 1 << 1;
144+
145+
const BITS: [u32; 2] = [BIT1, BIT2];
146+
const STRING: &str = "bitstring";
147+
148+
struct BitsNStrings<'a> {
149+
mybits: [u32; 2],
150+
mystring: &'a str,
151+
}
152+
153+
const BITS_N_STRINGS: BitsNStrings = BitsNStrings {
154+
mybits: BITS,
155+
mystring: STRING,
156+
};
157+
```
158+
159+
Note that if the `static` or `const` items include function or closure
160+
references, which themselves include references, the compiler will first try
161+
the standard elision rules ([see discussion in the nomicon][elision-nomicon]).
162+
If it is unable to resolve the lifetimes by its usual rules, it will default to
163+
using the `'static` lifetime. By way of example:
164+
165+
```rust,ignore
166+
// Resolved as `fn<'a>(&'a str) -> &'a str`.
167+
const RESOLVED_SINGLE: fn(&str) -> &str = ..
168+
169+
// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`.
170+
const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..
171+
172+
// There is insufficient information to bound the return reference lifetime
173+
// relative to the argument lifetimes, so the signature is resolved as
174+
// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
175+
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
176+
```
177+
178+
[RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
179+
[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md
180+
[elision-nomicon]: ../nomicon/lifetime-elision.html

Diff for: src/types.md

+5-60
Original file line numberDiff line numberDiff line change
@@ -462,66 +462,11 @@ type signature of `print`, and the cast expression in `main`.
462462
### Trait Object Lifetime Bounds
463463

464464
Since a trait object can contain references, the lifetimes of those references
465-
need to be expressed as part of the trait object. The assumed lifetime of
466-
references held by a trait object is called its *default object lifetime bound*.
467-
These were defined in [RFC 599] and amended in [RFC 1156].
465+
need to be expressed as part of the trait object. This lifetime is written as
466+
`Trait + 'a`. There are [defaults] that allow this lifetime to usually be
467+
infered with a sensible choice.
468468

469-
For traits that themselves have no lifetime parameters:
470-
* If there is a unique bound from the containing type then that is the default.
471-
* If there is more than one bound from the containing type then an explicit
472-
bound must be specified.
473-
* Otherwise the default bound is `'static`.
474-
475-
```rust,ignore
476-
// For the following trait...
477-
trait Foo { }
478-
479-
// These two are the same as Box<T> has no lifetime bound on T
480-
Box<Foo>
481-
Box<Foo + 'static>
482-
483-
// ...and so are these:
484-
impl Foo {}
485-
impl Foo + 'static {}
486-
487-
// ...so are these, because &'a T requires T: 'a
488-
&'a Foo
489-
&'a (Foo + 'a)
490-
491-
// std::cell::Ref<'a, T> also requires T: 'a, so these are the same
492-
std::cell::Ref<'a, Foo>
493-
std::cell::Ref<'a, Foo + 'a>
494-
495-
// This is an error:
496-
struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b>
497-
TwoBounds<'a, 'b, Foo> // Error: the lifetime bound for this object type cannot
498-
// be deduced from context
499-
500-
```
501-
502-
The `+ 'static` and `+ 'a` refer to the default bounds of those kinds of trait
503-
objects, and also to how you can directly override them. Note that the innermost
504-
object sets the bound, so `&'a Box<Foo>` is still `&'a Box<Foo + 'static>`.
505-
506-
For traits that have a single lifetime _bound_ of their own then, instead of
507-
infering 'static as the default bound, the bound on the trait is used instead
508-
509-
```rust,ignore
510-
// For the following trait...
511-
trait Bar<'a>: 'a { }
512-
513-
// ...these two are the same:
514-
Box<Bar<'a>>
515-
Box<Bar<'a> + 'a>
516-
517-
// ...and so are these:
518-
impl<'a> Foo<'a> {}
519-
impl<'a> Foo<'a> + 'a {}
520-
521-
// This is still an error:
522-
struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b>
523-
TwoBounds<'a, 'b, Foo<'c>>
524-
```
469+
[defaults]: lifetime-elision.html#elision-and-defaults-in-trait-objects
525470

526471
## Type parameters
527472

@@ -587,4 +532,4 @@ The notation `&self` is a shorthand for `self: &Self`.
587532
[auto traits]: special-types-and-traits.html#auto-traits
588533
[object safe]: items/traits.html#object-safety
589534
[issue 47010]: https://github.com/rust-lang/rust/issues/47010
590-
[issue 33140]: https://github.com/rust-lang/rust/issues/33140
535+
[issue 33140]: https://github.com/rust-lang/rust/issues/33140

0 commit comments

Comments
 (0)