Skip to content

Commit 0566e5b

Browse files
committed
Add admonition about pointer vs pointee capturing
There's some surprising nuance to what gets captured when reading the length of a slice with a slice pattern. Let's add an admonition about this.
1 parent 6a6295d commit 0566e5b

File tree

1 file changed

+27
-23
lines changed

1 file changed

+27
-23
lines changed

src/types/closure.md

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -378,29 +378,33 @@ r[type.closure.capture.precision.slice-patterns]
378378
r[type.closure.capture.precision.slice-patterns.slices]
379379
Matching a slice against a [slice pattern][patterns.slice] other than one with only a single [rest pattern][patterns.rest] (i.e. `[..]`) is treated as a read of the length from the slice and captures the slice by `ImmBorrow`.
380380

381-
```rust,compile_fail,E0502
382-
let x: &mut [u8] = &mut [];
383-
let c = || match x { // Captures `*x` by `ImmBorrow`.
384-
&mut [] => (),
385-
// ^^
386-
// This matches a slice of exactly zero elements. To know whether the
387-
// scrutinee matches, the length must be read, causing the slice to
388-
// be captured.
389-
_ => (),
390-
};
391-
let _ = &mut *x; // ERROR: Cannot borrow `*x` as mutable.
392-
c();
393-
```
394-
395-
```rust,no_run
396-
let x: &mut [u8] = &mut [];
397-
let c = || match x { // Does not capture `*x`.
398-
[..] => (),
399-
// ^^ Rest pattern.
400-
};
401-
let _ = &mut *x; // OK: `*x` can be borrow here.
402-
c();
403-
```
381+
> [!NOTE]
382+
> Perhaps surprisingly, even though the length is contained in the (wide) *pointer* to the slice, it is the place of the *pointee* (the slice) that is treated as read and is captured.
383+
>
384+
> ```rust,no_run
385+
> fn f<'l: 's, 's>(x: &'s mut &'l [u8]) -> impl Fn() + 'l {
386+
> // The closure outlives `'l` because it captures `**x`. If
387+
> // instead it captured `*x`, it would not live long enough
388+
> // to satisfy the `impl Fn() + 'l` bound.
389+
> || match *x { // Captures `**x` by `ImmBorrow`.
390+
> &[] => (),
391+
> _ => (),
392+
> }
393+
> }
394+
> ```
395+
>
396+
> In this way, the behavior is consistent with dereferencing to the slice in the scrutinee.
397+
>
398+
> ```rust,no_run
399+
> fn f<'l: 's, 's>(x: &'s mut &'l [u8]) -> impl Fn() + 'l {
400+
> || match **x { // Captures `**x` by `ImmBorrow`.
401+
> [] => (),
402+
> _ => (),
403+
> }
404+
> }
405+
> ```
406+
>
407+
> For details, see [Rust PR #138961](https://github.com/rust-lang/rust/pull/138961).
404408
405409
r[type.closure.capture.precision.slice-patterns.arrays]
406410
As the length of an array is fixed by its type, matching an array against a slice pattern does not by itself capture the place.

0 commit comments

Comments
 (0)