Closed
Description
Given the following code:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=bfca5a5df52348cba46546d72a36ccb6
fn testcase(items: &[u64]) -> Abc {
let mut abc = Abc { bar: Vec::new() };
items.iter().for_each(|item| abc.update(*item));
abc
}
struct Abc {
bar: Vec<u64>,
}
impl Abc {
fn update(mut self, bar: u64) {
// ^^^^^^^^ the issue is here, this should be `&mut self`
self.bar.push(bar);
}
}
The current output is:
error[[E0507]](https://doc.rust-lang.org/nightly/error-index.html#E0507): cannot move out of `abc`, a captured variable in an `FnMut` closure
[--> src/lib.rs:3:34
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
2 | let mut abc = Abc { bar: Vec::new() };
| ------- captured outer variable
3 | items.iter().for_each(|item| abc.update(*item));
| -------^^^--------------
| | |
| | move occurs because `abc` has type `Abc`, which does not implement the `Copy` trait
| captured by this `FnMut` closure
warning: variable does not need to be mutable
[--> src/lib.rs:2:9
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
2 | let mut abc = Abc { bar: Vec::new() };
| ----^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[[E0382]](https://doc.rust-lang.org/nightly/error-index.html#E0382): use of moved value: `abc`
[--> src/lib.rs:4:5
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
2 | let mut abc = Abc { bar: Vec::new() };
| ------- move occurs because `abc` has type `Abc`, which does not implement the `Copy` trait
3 | items.iter().for_each(|item| abc.update(*item));
| ------ --- variable moved due to use in closure
| |
| value moved into closure here
4 | abc
| ^^^ value used here after move
This diagnostic was confusing to me, since:
- It doesn't mention the reason why
update()
takes ownership - It talks about the
Copy
trait, which whilst true, isn't really the correct way to fix this
Ideally the output should look like:
...
...
note: this function takes ownership of the receiver `self`, which moves `abc`
[--> src/lib.rs:12:19
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
12 | fn update(mut self, bar: u64) {
| ^^^^
ie: Have a note
that explains the root issue - which is that the mut self
takes ownership - and thus hopefully allow users to realise it should be &mut self
in the definition of update()
, rather than the problem being in testcase()
.
Notably, if I change the implementation to use a for loop (rather than a closure with .forEach()
):
fn testcase(items: &[u64]) -> Abc {
let mut abc = Abc { bar: Vec::new() };
for item in items {
abc.update(*item);
}
abc
}
...then the output already includes the above suggestion:
warning: variable does not need to be mutable
[--> src/lib.rs:2:9
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
2 | let mut abc = Abc { bar: Vec::new() };
| ----^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[[E0382]](https://doc.rust-lang.org/nightly/error-index.html#E0382): use of moved value: `abc`
[--> src/lib.rs:4:9
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
2 | let mut abc = Abc { bar: Vec::new() };
| ------- move occurs because `abc` has type `Abc`, which does not implement the `Copy` trait
3 | for item in items {
4 | abc.update(*item);
| ^^^ ------------- `abc` moved due to this method call, in previous iteration of loop
|
note: this function takes ownership of the receiver `self`, which moves `abc`
[--> src/lib.rs:14:19
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
14 | fn update(mut self, bar: u64) {
| ^^^^
Metadata
Metadata
Assignees
Labels
Area: Closures (`|…| { … }`)Area: Messages for errors, warnings, and lintsDiagnostics: Confusing error or lint; hard to understand for new users.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.Relevant to the compiler team, which will review and decide on the PR/issue.