рддреНрд░реБрдЯрд┐: рдПрдХ
FnMut
рдХреНрд▓реЛрдЬрд░ рдореЗрдВ рдХреИрдкреНрдЪрд░ рдХрд┐рдП рдЧрдП рдмрд╛рд╣рд░реА рдЪрд░ рд╕реЗ рдмрд╛рд╣рд░ рдирд╣реАрдВ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
struct Foo {
a: i32,
b: i32,
bar: Bar,
}
struct Bar;
impl Bar {
fn f<F: FnMut()>(&self, mut f: F) {
f();
}
}
fn main() {
let mut foo = Foo { a: 1, b: 2, bar: Bar };
let a = &mut foo.a;
let b = &mut foo.b;
(|| { // works
*if true {a} else {b} = 42;
})();
let mut foo = Foo { a: 1, b: 2, bar: Bar };
let a = &mut foo.a;
let b = &mut foo.b;
foo.bar.f(|| { // doesn't work
*if true {a} else {b} = 42;
});
}
https://play.rust-lang.org/?gist=4ce6948a92c2fcb281b3cade8574691d&version=nightly
рд▓реЗрдХрд┐рди рджреВрд╕рд░рд╛ рдорд╛рдорд▓рд╛ рднреА рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП!
рдпрджрд┐ рдЖрдк FnMut рдХреЛ FnOnce рдореЗрдВ рдмрджрд▓рддреЗ рд╣реИрдВ рддреЛ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рд▓реЗрдХрд┐рди рдпрд╣ FnMut рдХреЗ рд╕рд╛рде рднреА рдХрд╛рдо рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛?
(рдмреАрдЯреАрдбрдмреНрд▓реНрдпреВ, рддреНрд░реБрдЯрд┐ рдпрд╣ рдХрд╣рдиреА рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЗрд╕реЗ FnOnce рддрдм рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред)
@ рдмреЙрд╕реНрдХреЛрдк рдХреНрдпреЛрдВрдХрд┐ рдЖрдк рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдЪреАрдЬреЛрдВ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдПрдХ FnMut
рдмрдВрдж рдХреЛ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
(рдмреАрдЯреАрдбрдмреНрд▓реНрдпреВ, рддреНрд░реБрдЯрд┐ рдпрд╣ рдХрд╣рдиреА рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЗрд╕реЗ FnOnce рддрдм рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред)
рдореИрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рд╣рдордд рдирд╣реАрдВ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореИрдВ рдЕрд╕рд╣рдордд рднреА рдирд╣реАрдВ рд╣реВрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рддреНрд░реБрдЯрд┐ рдХрд╛ рдирд┐рджрд╛рди рдХрд░рдирд╛ рдЕрдХреНрд╕рд░ рдХрдард┐рди рд╣реЛрддрд╛ рд╣реИред рдпрд╣рд╛рдВ рдПрдХ рддрд░рд╣ рдХрд╛ рддрдирд╛рд╡ рд╣реИ: рдХреНрд▓реЛрдЬрд░ рдПрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ (рдПрдХ рдЪрд╛рд▓) рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди f
рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдЗрд╕рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВ (рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд▓реЛрдЬрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬрд┐рд╕реЗ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ)ред рдпрд╣ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рддреНрд░реБрдЯрд┐ рдореЗрдВ рд╣реИ (рдЗрд╕реЗ FnOnce
рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП) рдпрд╛ рдмрдВрдж рдХрд░рдирд╛ рдЧрд▓рдд рд╣реИ (рдпрд╣ рдЙрди рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реИ рдЬреЛ рдЗрд╕реЗ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП)ред рдХрдо рд╕реЗ рдХрдо, рд╣рдо рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд┐рджрд╛рди рдореЗрдВ рдЗрд╕ 'рддрдирд╛рд╡' рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХрд╛ рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВред
рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдХреНрд▓реЛрдЬрд░ рдХреЛ рд╕реАрдзреЗ f
рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рд╣рдо рдХреБрдЫ рд╣рдж рддрдХ рдмреЗрд╣рддрд░ рддреНрд░реБрдЯрд┐ рджреЗрддреЗ рд╣реИрдВ :
error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
--> src/main.rs:19:19
|
19 | let closure = || { // doesn't work
| ___________________^
20 | | *if true {a} else {b} = 42;
21 | | };
| |_____^
22 | foo.bar.f(closure);
| - the requirement to implement `FnMut` derives from here
|
note: closure is `FnOnce` because it moves the variable `a` out of its environment
--> src/main.rs:20:19
|
20 | *if true {a} else {b} = 42;
|
рдпрд╣ рдПрдХ рдмрдВрдж рд╣реИ "рдкрд░рд┐рднрд╛рд╖рд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛" рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ @estebank (рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐? рдпрд╛ рдпрд╣ рдХрд┐рд╕реА рдФрд░ рдерд╛ ...) рдореЗрдВ рдбрд╛рд▓ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреНрд░реИрдХрд┐рдВрдЧ рдХреЗ рдХрд╛рд░рдг рд╣реИред рдЕрднреА, рд╡рд╣ рдЬрд╛рдБрдЪ рдЪрд▓рди рдореЗрдВ рдирд╣реАрдВ рдЖ рд░рд╣реА рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рддрдп рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдХрд┐ рдмрдВрдж рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП FnMut
рдХреЗрд╡рд▓ f
рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХреЗ рдХрд╛рд░рдгред
рдЗрд╕ рдХреЛрдб рдореЗрдВ рдРрд╕рд╛ рд╣реЛрддрд╛ рд╣реИ:
рдЬрдм рд╣рдо рдЙрд╕ рд░рд╛рд╕реНрддреЗ рд╕реЗ рдиреАрдЪреЗ рдЬрд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдХрднреА рднреА рдЗрд╕ рддрд░рд╣ рдХреЗ "рдореВрд▓" рдХреЛ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд, рдЕрдкрд╡рд░ рдЕрдиреБрдорд╛рди рдЬреЛ рдЕрдиреНрдпрдерд╛ рдХрд┐рдХ рдХрд░рддрд╛ рд╣реИ рд╡рд╣ рдРрд╕рд╛ рдХрд░рддрд╛ рд╣реИ:
рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рд╕рдВрднрд╡рдд: closure_kind_origins_mut
рдореЗрдВ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдФрд░ рдлрд┐рд░ рдЙрдзрд╛рд░ рдЬрд╛рдВрдЪ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рддрдм рд╣рдо рдПрдХ рддреНрд░реБрдЯрд┐ рджреЗ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕реЗ:
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> src/main.rs:20:19
|
17 | let a = &mut foo.a;
| - captured outer variable
...
20 | *if true {a} else {b} = 42;
| ^ cannot move out of captured outer variable in an `FnMut` closure
note: closure is `FnMut` because of the requirements of `f()`
--> src/main.rs:19:19
|
19 | foo.bar.f(||
| ^^^^^^^^^
|
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
@ рдмреЙрд╕реНрдХреЛрдк рдХреНрдпреЛрдВрдХрд┐ рдЖрдк рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдЪреАрдЬреЛрдВ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдПрдХ
FnMut
рдмрдВрдж рдХреЛ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИредрдореИрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рд╣рдордд рдирд╣реАрдВ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореИрдВ рдЕрд╕рд╣рдордд рднреА рдирд╣реАрдВ рд╣реВрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рддреНрд░реБрдЯрд┐ рдХрд╛ рдирд┐рджрд╛рди рдХрд░рдирд╛ рдЕрдХреНрд╕рд░ рдХрдард┐рди рд╣реЛрддрд╛ рд╣реИред рдпрд╣рд╛рдВ рдПрдХ рддрд░рд╣ рдХрд╛ рддрдирд╛рд╡ рд╣реИ: рдХреНрд▓реЛрдЬрд░ рдПрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ (рдПрдХ рдЪрд╛рд▓) рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди
f
рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдЗрд╕рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВ (рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд▓реЛрдЬрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬрд┐рд╕реЗ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ)ред рдпрд╣ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рддреНрд░реБрдЯрд┐ рдореЗрдВ рд╣реИ (рдЗрд╕реЗFnOnce
рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП) рдпрд╛ рдмрдВрдж рдХрд░рдирд╛ рдЧрд▓рдд рд╣реИ (рдпрд╣ рдЙрди рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реИ рдЬреЛ рдЗрд╕реЗ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП)ред рдХрдо рд╕реЗ рдХрдо, рд╣рдо рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд┐рджрд╛рди рдореЗрдВ рдЗрд╕ 'рддрдирд╛рд╡' рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХрд╛ рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВредрджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдХреНрд▓реЛрдЬрд░ рдХреЛ рд╕реАрдзреЗ
f
рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рд╣рдо рдХреБрдЫ рд╣рдж рддрдХ рдмреЗрд╣рддрд░ рддреНрд░реБрдЯрд┐ рджреЗрддреЗ рд╣реИрдВ :рдпрд╣ рдПрдХ рдмрдВрдж рд╣реИ "рдкрд░рд┐рднрд╛рд╖рд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛" рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ @estebank (рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐? рдпрд╛ рдпрд╣ рдХрд┐рд╕реА рдФрд░ рдерд╛ ...) рдореЗрдВ рдбрд╛рд▓ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреНрд░реИрдХрд┐рдВрдЧ рдХреЗ рдХрд╛рд░рдг рд╣реИред рдЕрднреА, рд╡рд╣ рдЬрд╛рдБрдЪ рдЪрд▓рди рдореЗрдВ рдирд╣реАрдВ рдЖ рд░рд╣реА рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рддрдп рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдХрд┐ рдмрдВрдж рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП
FnMut
рдХреЗрд╡рд▓f
рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХреЗ рдХрд╛рд░рдгредрдЗрд╕ рдХреЛрдб рдореЗрдВ рдРрд╕рд╛ рд╣реЛрддрд╛ рд╣реИ:
https://github.com/rust-lang/rust/blob/70f7d5842f29d4900f24420b030f144d21f3c5fc/src/librustc_typeck/check/closure.rs#L151 -L155
рдЬрдм рд╣рдо рдЙрд╕ рд░рд╛рд╕реНрддреЗ рд╕реЗ рдиреАрдЪреЗ рдЬрд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдХрднреА рднреА рдЗрд╕ рддрд░рд╣ рдХреЗ "рдореВрд▓" рдХреЛ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд, рдЕрдкрд╡рд░ рдЕрдиреБрдорд╛рди рдЬреЛ рдЕрдиреНрдпрдерд╛ рдХрд┐рдХ рдХрд░рддрд╛ рд╣реИ рд╡рд╣ рдРрд╕рд╛ рдХрд░рддрд╛ рд╣реИ:
https://github.com/rust-lang/rust/blob/70f7d5842f29d4900f24420b030f144d21f3c5fc/src/librustc_typeck/check/upvar.rs#L182 -L188
рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рд╕рдВрднрд╡рдд:
closure_kind_origins_mut
рдореЗрдВ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдФрд░ рдлрд┐рд░ рдЙрдзрд╛рд░ рдЬрд╛рдВрдЪ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рддрдм рд╣рдо рдПрдХ рддреНрд░реБрдЯрд┐ рджреЗ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕реЗ: