Rust 闭包

闭包只是定义了代码,存储代码,并不是执行,切记。

Rust的闭包类型分为三种:
1.Fn
2.FnMut
3.FnOnce

不同之处:
1.它们的调用方法分别采用&self、&mut self和self,这意味着Fn对其捕获具有不可变的访问权限,FnMut获得可变的访问权限,FnOnce可以获得所有权。
2.Fn和FnMut类型的闭包可以执行多次,而FnOnce类型的闭包只能执行一次。

move关键字:
1.如果没有实现Copy,就是move语义,会发生移动。
2.如果实现Copy,则是copy语义,会发生拷贝。
值得注意的是move与闭包的类型没有关系

示例代码:
1.Fn

#[derive(Debug)]
struct Person {
    age: usize,
}

impl Person {
    fn print(self) {
        println!("{:?}", self);
    }

    fn print_ref(&self) {
        println!("{:?}", self);
    }

    fn print_mut_ref(&mut self) {
        println!("{:?}", self);
    }
}

fn call_fn<F: Fn()>(f: F) {
    f();
}

fn main() {
    let mut person = Person { age: 18 };

    call_fn(|| {
    	// Fn 可以获得不可变的访问权限
        person.print_ref();

        // Fn 不可以获得可变的访问权限
        // person.print_mut_ref();

        // Fn 不可以获得所有权
        // person.print();
    });
}

2.FnMut

#[derive(Debug)]
struct Person {
    age: usize,
}

impl Person {
    fn print(self) {
        println!("{:?}", self);
    }

    fn print_ref(&self) {
        println!("{:?}", self);
    }

    fn print_mut_ref(&mut self) {
        println!("{:?}", self);
    }
}

fn call_fn_mut<F: FnMut()>(mut f: F) {
    f();
}

fn main() {
    let mut person = Person { age: 18 };

    call_fn_mut(|| {
        // FnMut 可以获得不可变的访问权限
        person.print_ref();

        // FnMut 可以获得可变的访问权限
        person.print_mut_ref();

        // FnMut 不可以获得所有权
        // person.print();
    });
}

3.FnOnce

#[derive(Debug)]
struct Person {
    age: usize,
}

impl Person {
    fn print(self) {
        println!("{:?}", self);
    }

    fn print_ref(&self) {
        println!("{:?}", self);
    }

    fn print_mut_ref(&mut self) {
        println!("{:?}", self);
    }
}

fn call_fn_once<F: FnOnce()>(f: F) {
    f();
}

fn main() {
    let mut person = Person { age: 18 };

    call_fn_once(|| {
        // FnOnce 可以获得不可变的访问权限
        person.print_ref();

        // FnOnce 可以获得可变的访问权限
        person.print_mut_ref();

        // FnOnce 可以获得所有权
        person.print();
    });
}

4.Fn/FnMut/FnOnce

fn call_fn_once<F>(f: F, s: String)
    where F: FnOnce(String) -> String
{
    let res = f(s);
    println!("res: {}", res);
}

fn call_fn_mut<F>(mut f: F, s: String)
    where F: FnMut(String) -> String
{
    let res = f(s);
    println!("res: {}", res);
}

fn call_fn<F>(f: F, s: String)
    where F: Fn(String) -> String
{
    let res = f(s);
    println!("res: {}", res);
}

fn main() {
    let name1 = "upfly".to_owned();
    let mut name2 = name1.clone();
    let name3 = name1.clone();

    // Fn
    let c1 = |s: String| -> String {
        println!("name1: {}", name1);
        s
    };

    // FnMut
    let c2 = |s: String| -> String {
        name2.push_str("666");
        println!("name2: {}", name2);
        s
    };

    // FnOnce
    let c3 = move |s: String| -> String {
        println!("name3: {}", name3);
        let _name: String = name3;
        s
    };

    // FnOnce 可以接受 Fn/FnMut/FnOnce
    // Ok
    // call_fn_once(c1, "fn_once fn".to_owned());
    // Ok
    // call_fn_once(c2, "fn_once fn_mut".to_owned());
    // Ok
    // call_fn_once(c3, "fn_once fn_once".to_owned());

    // FnMut 只能接受 Fn 和 FnMut
    // Ok
    // call_fn_mut(c1, "fn_mut fn".to_owned());
    // Ok
    // call_fn_mut(c2, "fn_mut fn_mut".to_owned());
    // Err
    // call_fn_mut(c3, "fn_mut fn_once".to_owned());

    // Fn 只能接受 Fn
    // Ok
    // call_fn(c1, "fn fn".to_owned());
    // Err
    // call_fn(c2, "fn fn_mut".to_owned());
    // Err
    // call_fn(c3, "fn fn_once".to_owned());
}

5.move

#[derive(Debug, Clone, Copy)]
struct Person {
    age: usize,
}

fn call_fn<F: Fn()>(f: F) {
    f();
}

fn main() {
    let person = Person { age: 18 };

    call_fn(move || {
        println!("{:?}", person);
    });

    // 不实现 Copy,报错 value borrowed here after move
    println!("{:?}", person);
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值