Skip to content

Instantly share code, notes, and snippets.

@nomyfan
Last active September 26, 2022 15:37
Show Gist options
  • Save nomyfan/e49941b5c7807f1e4bce064d17f1b0d0 to your computer and use it in GitHub Desktop.
Save nomyfan/e49941b5c7807f1e4bce064d17f1b0d0 to your computer and use it in GitHub Desktop.
Rust Fn vs. FnMut vs. FnOnce
#[derive(Copy, Clone)]
struct Foo {
val: i32,
}
impl Foo {
fn new(val: i32) -> Self {
Foo { val }
}
}
struct Foo1 {
val: i32,
}
fn impl_fn_mut_trait<F: FnMut()>(_closure: &F) {}
fn impl_fn_once_trait<F: FnOnce()>(_closure: &F) {}
fn impl_fn_trait<F: Fn()>(_closure: &F) {}
fn impl_copy_trait<F: Copy>(_closure: &F) {}
fn run_fn_once<F: FnOnce()>(f: F) {
f();
// f(); // Compile error
}
fn run_fn_mut<F: FnMut()>(mut f: F) {
f();
f();
}
fn run_fn<F: Fn()>(f: F) {
f();
f();
}
// Q:为什么捕获的变量Copy了,那么闭包就实现了Copy trait?
// A:如果捕获的变量都可以copy,那么意味着匿名闭包结构体也可以copy。
fn main() {
let mut foo = Foo::new(0);
// impl FnMut + Copy
let mut closure1 = move || { // move会触发foo的copy
foo.val += 1;
};
impl_fn_mut_trait(&closure1);
impl_copy_trait(&closure1);
impl_fn_once_trait(&closure1);
// impl_fn_trait(&closure1); // Not satisfied.
closure1();
closure1();
println!("closure1 {}", &foo.val);
let mut foo = Foo::new(0);
// impl FnMut
let mut closure2 = || { // 这个闭包只是对foo使用了mut借用语义
foo.val += 1;
};
impl_fn_mut_trait(&closure2);
// impl_copy_trait(&closure2); // Not implemented.
impl_fn_once_trait(&closure2);
// impl_fn_trait(&closure2); // Not satisfied.
closure2();
closure2();
println!("closure2 {}", &foo.val);
let foo = Foo::new(0);
// impl Fn + Copy
let closure3 = move || {
println!("println! in closure3 {}", foo.val);
};
impl_fn_mut_trait(&closure3);
impl_copy_trait(&closure3);
impl_fn_once_trait(&closure3);
impl_fn_trait(&closure3);
closure3();
closure3();
println!("{}", &foo.val);
let mut foo = Foo1 { val: 0 };
// impl FnMut
let mut closure4 = move || {
foo.val += 1;
println!("println! in closure4 {}", foo.val);
};
impl_fn_mut_trait(&closure4);
// impl_copy_trait(&closure4);
impl_fn_once_trait(&closure4);
// impl_fn_trait(&closure4);
closure4();
closure4();
// println!("{}", &foo.val); // Borrow error
let mut foo = Foo1 {val: 0};
// impl FnOnce
let closure5 = move || {
foo.val += 1;
println!("println! in closure5 {}", foo.val);
drop(foo);
};
// impl_fn_mut_trait(&closure5);
// impl_copy_trait(&closure5);
impl_fn_once_trait(&closure5);
// impl_fn_trait(&closure5);
closure5();
// closure5(); // Compile error, it's FnOnce
// println!("closure5 {}", &foo.val); // Borrow error
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment