Rust中的Fn、FnOnce、FnMut闭包详解

闭包会自动实现FnFnOnceFnMut这三个trait中的任意一个,这取决于闭包在调用过程中对捕获变量的使用;

先了解Rust中的借用规则:

  • 在给定的作用域内,可以有多个不可变引用;
  • 在给定的作用域内,只允许有一个可变引用;
  • 在给定的作用域内,不允许同时存在可变引用和不可变引用;

Fn 闭包

如果闭包捕获了外部环境中的变量,并且在闭包内部仅对这些变量进行不可变访问,则闭包会自动实现Fntrait;

实现了Fntrait的闭包能被多次调用;

fn main() {
    let str = "hello".to_string();

    let closure = || {
        println!("{}",str);
    };

    call_closure(closure);
    call_closure(closure);
    call_closure(closure);
    call_closure(closure);
    println!("{}",str);

}

fn call_closure(f: impl Fn()){f();}

这段代码中,闭包内部只对捕获到的变量str进行了不可变访问,所以它将自动实现Fntrait;

根据借用规则,允许存在多个str的不可变引用,所以这个闭包能被多次调用;

FnOnce 闭包

如果闭包捕获了外部环境中的变量,并且在闭包内部对其中至少一个变量进行了所有权转移,则闭包会自动实现FnOncetrait;

实现了FnOncetrait的闭包只允许被调用一次;

fn main() {
    let str = "hello".to_string();

    let closure = move || {
        let str2 = str;
        println!("{}",str2);
    };

    call_closure(closure);
    //call_closure(closure); //只允许调用一次
    //println!("{}",str); //所有权被转移,无法再访问
    
}

fn call_closure(f: impl FnOnce()){f();}

这段代码中,闭包内部将捕获变量str的所有权转移到了str2move关键字表示闭包会获取捕获变量的所有权,而不仅仅只是引用他们;

由于该闭包发生了捕获变量的所有权转移,所以它会自动实现FnOncetrait;

由于str的所有权被转移,str将被标记为不可使用,这也是FnOnce闭包只能被调用一次的原因;

FnMut 闭包

如果闭包捕获了外部环境中的变量,并且在闭包内部对其中至少一个变量进行了可变访问,则闭包会自动实现FnMuttrait;

实现了FnMuttrait的闭包允许被多次调用;

fn main() {
    let mut str = "hello".to_string();

    let mut closure = || {
        str.push_str(" world");
        println!("{}",str);
    };

    //println!("{}",str); //不可访问

    call_closure(&mut closure);
    call_closure(&mut closure);
    call_closure(&mut closure);
    
    println!("{}",str); //可以访问

}

fn call_closure(f: &mut impl FnMut()){f();}

这段代码中,闭包内部发生了对捕获变量str的可变访问,该闭包将自动实现FnMuttrait;

9行代码中,str不可变引用与闭包中捕获变量str的可变引用作用域重叠,违反借用规则;

15行代码中,str不可变引用与闭包中捕获变量str的可变引用作用域没有重叠,没有违反借用规则;

原创内容,如需转载,请注明出处;

本文地址: https://www.perfcode.com/p/fn-fnonce-fnmut.html

分类: 计算机技术
推荐阅读:
使用Rust实现CRC32算法 CRC32是一种循环冗余校验码(Cyclic Redundancy Check)算法,通常用于数据传输或存储中的错误检测。该算法通过对输入数据进行位操作和模2除法来生成一个32位的校验码,该校验码可以用于验证输入数据是否已经损坏或被篡改。
为pm.max_children设置一个合理的值 pm.max_children这个值在php-fpm中至关重要;其意义为:表示php-fpm 能启动的子进程的最大数量;它能影响你网站的打开速度以及服务器的开销。
Rust debug_assert_eq宏的用法和示例 在Rust语言中,debug_assert_eq宏专门用于进行调试时的值相等性检查。它类似于assert_eq宏,但有一个重要的区别:debug_assert_eq只能在Rust的debug模式下进行检查,这意味着在发布应用程序时,所有的debug_assert_eq检查都会被编译器完全移除,不会影响最终的执行代码。
配置Nginx实现屏蔽爬虫IP 防止爬虫采集绝对是一个站长需要做的事;且不说站内资源被爬走,单是爬虫采集时消耗的服务器资源可能就够很多站长心疼了。
Python open()函数 open()函数是Python中用于打开文件的内置函数。它可以打开一个文件,并返回一个文件对象,以便对文件进行读取、写入、追加等操作。
Rust解析JSON,结构体序列化和反序列化 JSON一种常用的由键值对组成的数据对象;本文将通过多个例子讲解在Rust中如何解析JSON内容,以及如何将结构体转换成JSON字符串。