Skip to content

Commit ec079d3

Browse files
authored
Merge pull request #249 from alercah/closures
Improve documentation on closure types.
2 parents 72751c5 + 07ccc1d commit ec079d3

File tree

1 file changed

+117
-20
lines changed

1 file changed

+117
-20
lines changed

src/types.md

+117-20
Original file line numberDiff line numberDiff line change
@@ -365,30 +365,101 @@ x = bo(5,7);
365365
## Closure types
366366

367367
A [closure expression] produces a closure value with a unique, anonymous type
368-
that cannot be written out.
368+
that cannot be written out. A closure type is approximately equivalent to a
369+
struct which contains the captured variables. For instance, the following
370+
closure:
369371

370-
Depending on the requirements of the closure, its type implements one or
371-
more of the closure traits:
372+
```rust
373+
fn f<F : FnOnce() -> String> (g: F) {
374+
println!("{}", g());
375+
}
376+
377+
let mut s = String::from("foo");
378+
let t = String::from("bar");
379+
380+
f(|| {
381+
s += &*t;
382+
s
383+
});
384+
// Prints "foobar".
385+
```
386+
387+
generates a closure type roughly like the following:
388+
389+
```rust,ignore
390+
struct Closure<'a> {
391+
s : String,
392+
t : &'a String,
393+
}
372394
373-
* `FnOnce`
374-
: The closure can be called once. A closure called as `FnOnce` can move out
375-
of its captured values.
395+
impl<'a> (FnOnce() -> String) for Closure<'a> {
396+
fn call_once(self) -> String {
397+
self.s += &*self.t;
398+
self.s
399+
}
400+
}
401+
```
376402

377-
* `FnMut`
378-
: The closure can be called multiple times as mutable. A closure called as
379-
`FnMut` can mutate values from its environment. `FnMut` inherits from
380-
`FnOnce` (i.e. anything implementing `FnMut` also implements `FnOnce`).
403+
so that the call to `f` works as if it were:
381404

382-
* `Fn` : The closure can be called multiple times through a shared reference. A
383-
closure called as `Fn` can neither move out from nor mutate captured
384-
variables, but read-only access to such values is allowed. Using `move` to
385-
capture variables by value is allowed so long as they aren't mutated or
386-
moved in the body of the closure. `Fn` inherits from `FnMut`, which itself
387-
inherits from `FnOnce`.
405+
```rust,ignore
406+
f(Closure{s: s, t: &t});
407+
```
388408

389-
Closures that don't use anything from their environment, called *non-capturing
390-
closures*, can be coerced to function pointers (`fn`) with the matching
391-
signature. To adopt the example from the section above:
409+
The compiler prefers to capture a closed-over variable by immutable borrow,
410+
followed by mutable borrow, by copy, and finally by move. It will pick the first
411+
choice of these that allows the closure to compile. If the `move` keyword is
412+
used, then all captures are by move or copy, regardless of whether a borrow
413+
would work. The `move` keyword is usually used to allow the closure to outlive
414+
the captured values, such as if the closure is being returned or used to spawn a
415+
new thread.
416+
417+
Composite types such as structs, tuples, and enums are always captured entirely,
418+
not by individual fields. It may be necessary to borrow into a local variable in
419+
order to capture a single field:
420+
421+
```rust
422+
# use std::collections::HashSet;
423+
#
424+
struct SetVec {
425+
set: HashSet<u32>,
426+
vec: Vec<u32>
427+
}
428+
429+
impl SetVec {
430+
fn populate(&mut self) {
431+
let vec = &mut self.vec;
432+
self.set.iter().for_each(|&n| {
433+
vec.push(n);
434+
})
435+
}
436+
}
437+
```
438+
439+
If, instead, the closure were to use `self.vec` directly, then it would attempt
440+
to capture `self` by mutable reference. But since `self.set` is already
441+
borrowed to iterate over, the code would not compile.
442+
443+
### Call traits and coercions
444+
445+
Closure types all implement `[FnOnce]`, indicating that they can be called once
446+
by consuming ownership of the closure. Additionally, some closures implement
447+
more specific call traits:
448+
449+
* A closure which does not move out of any captured variables implements
450+
`[FnMut]`, indicating that it can be called by mutable reference.
451+
452+
* A closure which does not mutate or move out of any captured variables
453+
implements `[Fn]`, indicating that it can be called by shared reference.
454+
455+
> Note: `move` closures may still implement `[Fn]` or `[FnMut]`, even though
456+
> they capture variables by move. This is because the traits implemented by a
457+
> closure type are determined by what the closure does with captured values, not
458+
> how it captures them.
459+
460+
*Non-capturing closures* are closures that don't capture anything from their
461+
environment. They can be coerced to function pointers (`fn`) with the matching
462+
signature.
392463

393464
```rust
394465
let add = |x, y| x + y;
@@ -400,6 +471,31 @@ let bo: Binop = add;
400471
x = bo(5,7);
401472
```
402473

474+
### Other traits
475+
476+
All closure types implement `[Sized]`. Additionally, closure types implement the
477+
following traits if allowed to do so by the types of the captures it stores:
478+
479+
* `[Clone]`
480+
* `[Copy]`
481+
* `[Sync]`
482+
* `[Send]`
483+
484+
The rules for `[Send]` and `[Sync]` match those for normal struct types, while
485+
`[Clone]` and `[Copy]` behave as if [derived][derive]. For `[Clone]`, the order
486+
of cloning of the captured variables is left unspecified.
487+
488+
Because captures are often by reference, the following general rules arise:
489+
490+
* A closure is `[Sync]` if all variables captured by mutable reference, copy, or
491+
move are `[Sync]`.
492+
* A closure is `[Send]` if all variables captured by shared reference are
493+
`[Sync]`, and all values captured by mutable reference, copy, or move are
494+
`[Send]`.
495+
* A closure is `[Clone]` or `[Copy]` if it does not capture any values by
496+
mutable reference, and if all values it captures by copy or move are `[Clone]`
497+
or `[Copy]`, respectively.
498+
403499
## Trait objects
404500

405501
A *trait object* is an opaque value of another type that implements a set of
@@ -593,6 +689,7 @@ impl Printable for String {
593689
[Clone]: special-types-and-traits.html#clone
594690
[Send]: special-types-and-traits.html#send
595691
[Sync]: special-types-and-traits.html#sync
692+
[derive]: attributes.html#derive
596693
[`Vec<T>`]: ../std/vec/struct.Vec.html
597694
[dynamically sized type]: dynamically-sized-types.html
598695
[dynamically sized types]: dynamically-sized-types.html
@@ -603,4 +700,4 @@ impl Printable for String {
603700
[auto traits]: special-types-and-traits.html#auto-traits
604701
[object safe]: items/traits.html#object-safety
605702
[issue 47010]: https://github.com/rust-lang/rust/issues/47010
606-
[issue 33140]: https://github.com/rust-lang/rust/issues/33140
703+
[issue 33140]: https://github.com/rust-lang/rust/issues/33140

0 commit comments

Comments
 (0)