μ€λ₯:
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μμλ μλνμ§ μλ μ΄μ λ 무μμ λκΉ?
(Btw, μ€λ₯λ FnOnceμ¬μΌ νλ€κ³ λ§ν΄μΌ ν©λλ€.)
@Boscop μ ν λ²λ§ μ΄λν μ μκΈ° λλ¬Έμ FnMut
ν΄λ‘μ λ λ λ² μ΄μ νΈμΆλ μ μμ΅λλ€.
(Btw, μ€λ₯λ 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 (λ΄ μκ°μ? μλλ©΄ λ€λ₯Έ μ¬λ μ΄μ λ₯Ό μΆμ νκΈ° μν΄ λ£μ μΆμ λλ¬Έμ
λλ€. νμ¬ f
μ μλͺ
λλ¬Έμ ν΄λ‘μ κ° FnMut
μ¬μΌ νλ€κ³ κ²°μ νκΈ° λλ¬Έμ ν΄λΉ κ²μ¬κ° μλνμ§ μμ΅λλ€.
μ΄ μ½λμμ λ°μν©λλ€.
μ°λ¦¬κ° κ·Έ κΈΈμ κ° λ μ°λ¦¬λ κ·Έ μ’ λ₯μ "μμ "μ μ μ₯νμ§ μμ΅λλ€. λμ‘°μ μΌλ‘, κ·Έλ μ§ μμΌλ©΄ μμλ upvar μΆλ‘ μ λ€μμ μνν©λλ€.
λ°λΌμ 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(||
| ^^^^^^^^^
|
κ°μ₯ μ μ©ν λκΈ
@Boscop μ ν λ²λ§ μ΄λν μ μκΈ° λλ¬Έμ
FnMut
ν΄λ‘μ λ λ λ² μ΄μ νΈμΆλ μ μμ΅λλ€.μ μ μΌλ‘ λμνμ§λ μμ§λ§ λμ νμ§λ
f
μ μλͺ μ μ΄λ₯Ό νμ©νμ§ μμ΅λλ€(λ λ² μ΄μ νΈμΆν μ μλ ν΄λ‘μ κ° νμνκΈ° λλ¬Έμ). μλͺ μ μ€λ₯κ° μκ±°λ(FnOnce
νμ©νλλ‘ μΌλ°νλμ΄μΌ ν¨) ν΄λ‘μ κ° μλͺ»λμμ μ μμ΅λλ€(νμ§ λ§μμΌ ν μΌμ νλ €κ³ ν¨). μ΅μν μ°λ¦¬λ μ§λ¨μμ μ΄ 'κΈ΄μ₯'μ μ ν¬μ°©νμ§ λͺ»νκ³ μμ΅λλ€.ν₯λ―Έλ‘κ²λ ν΄λ‘μ κ°
f
λν μΈμλ‘ μ§μ μ 곡λμ§ μμΌλ©΄ μ½κ° λ λμ μ€λ₯κ° λ°μν©λλ€ .μ΄κ²μ @estebank (λ΄ μκ°μ? μλλ©΄ λ€λ₯Έ μ¬λ μ΄μ λ₯Ό μΆμ νκΈ° μν΄ λ£μ μΆμ λλ¬Έμ λλ€. νμ¬
f
μ μλͺ λλ¬Έμ ν΄λ‘μ κ°FnMut
μ¬μΌ νλ€κ³ κ²°μ νκΈ° λλ¬Έμ ν΄λΉ κ²μ¬κ° μλνμ§ μμ΅λλ€.μ΄ μ½λμμ λ°μν©λλ€.
https://github.com/rust-lang/rust/blob/70f7d5842f29d4900f24420b030f144d21f3c5fc/src/librustc_typeck/check/closure.rs#L151 -L155
μ°λ¦¬κ° κ·Έ κΈΈμ κ° λ μ°λ¦¬λ κ·Έ μ’ λ₯μ "μμ "μ μ μ₯νμ§ μμ΅λλ€. λμ‘°μ μΌλ‘, κ·Έλ μ§ μμΌλ©΄ μμλ upvar μΆλ‘ μ λ€μμ μνν©λλ€.
https://github.com/rust-lang/rust/blob/70f7d5842f29d4900f24420b030f144d21f3c5fc/src/librustc_typeck/check/upvar.rs#L182 -L188
λ°λΌμ
closure_kind_origins_mut
μ μ΄λ€ μ’ λ₯μ μ 보λ₯Ό μ μ₯ν λ€μ μ°¨μ μνλ₯Ό κ°μ ν΄μΌ ν©λλ€. κ·Έλ¬λ©΄ λ€μκ³Ό κ°μ μ€λ₯κ° λ°μν μ μμ΅λλ€.