Skip to content

Commit 47266f4

Browse files
authored
Merge pull request #328 from alercah/uniq-borrow
Add explanation of unique immutable borrows.
2 parents 5b2346a + fdf136e commit 47266f4

File tree

1 file changed

+43
-11
lines changed

1 file changed

+43
-11
lines changed

src/types.md

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,16 @@ f(Closure{s: s, t: &t});
415415
```
416416

417417
The compiler prefers to capture a closed-over variable by immutable borrow,
418-
followed by mutable borrow, by copy, and finally by move. It will pick the first
419-
choice of these that allows the closure to compile. If the `move` keyword is
420-
used, then all captures are by move or copy, regardless of whether a borrow
421-
would work. The `move` keyword is usually used to allow the closure to outlive
422-
the captured values, such as if the closure is being returned or used to spawn a
423-
new thread.
418+
followed by unique immutable borrow (see below), by mutable borrow, and finally
419+
by move. It will pick the first choice of these that allows the closure to
420+
compile. The choice is made only with regards to the contents of the closure
421+
expression; the compiler does not take into account surrounding code, such as
422+
the lifetimes of involved variables.
423+
424+
If the `move` keyword is used, then all captures are by move or, for `Copy`
425+
types, by copy, regardless of whether a borrow would work. The `move` keyword is
426+
usually used to allow the closure to outlive the captured values, such as if the
427+
closure is being returned or used to spawn a new thread.
424428

425429
Composite types such as structs, tuples, and enums are always captured entirely,
426430
not by individual fields. It may be necessary to borrow into a local variable in
@@ -448,6 +452,34 @@ If, instead, the closure were to use `self.vec` directly, then it would attempt
448452
to capture `self` by mutable reference. But since `self.set` is already
449453
borrowed to iterate over, the code would not compile.
450454

455+
### Unique immutable borrows in captures
456+
457+
Captures can occur by a special kind of borrow called a _unique immutable
458+
borrow_, which cannot be used anywhere else in the language and cannot be
459+
written out explicitly. It occurs when modifying the referent of a mutable
460+
reference, as in the following example:
461+
462+
```rust
463+
let mut b = false;
464+
let x = &mut b;
465+
{
466+
let mut c = || { *x = true; };
467+
// The following line is an error:
468+
// let y = &x;
469+
c();
470+
}
471+
let z = &x;
472+
```
473+
474+
In this case, borrowing `x` mutably is not possible, because `x` is not `mut`.
475+
But at the same time, borrowing `x` immutably would make the assignment illegal,
476+
because a `& &mut` reference may not be unique, so it cannot safely be used to
477+
modify a value. So a unique immutable borrow is used: it borrows `x` immutably,
478+
but like a mutable borrow, it must be unique. In the above example, uncommenting
479+
the declaration of `y` will produce an error because it would violate the
480+
uniqueness of the closure's borrow of `x`; the declaration of z is valid because
481+
the closure's lifetime has expired at the end of the block, releasing the borrow.
482+
451483
### Call traits and coercions
452484

453485
Closure types all implement [`FnOnce`], indicating that they can be called once
@@ -496,12 +528,12 @@ of cloning of the captured variables is left unspecified.
496528
Because captures are often by reference, the following general rules arise:
497529

498530
* A closure is [`Sync`] if all captured variables are [`Sync`].
499-
* A closure is [`Send`] if all variables captured by shared reference are
500-
[`Sync`], and all values captured by mutable reference, copy, or move are
501-
[`Send`].
531+
* A closure is [`Send`] if all variables captured by non-unique immutable
532+
reference are [`Sync`], and all values captured by unique immutable or mutable
533+
reference, copy, or move are [`Send`].
502534
* A closure is [`Clone`] or [`Copy`] if it does not capture any values by
503-
mutable reference, and if all values it captures by copy or move are
504-
[`Clone`] or [`Copy`], respectively.
535+
unique immutable or mutable reference, and if all values it captures by copy
536+
or move are [`Clone`] or [`Copy`], respectively.
505537

506538
## Trait objects
507539

0 commit comments

Comments
 (0)