美文网首页
rust--匿名函数FnOnce/FnMut/Fn

rust--匿名函数FnOnce/FnMut/Fn

作者: 极光火狐狸 | 来源:发表于2018-09-03 20:35 被阅读160次
    // 匿名函数中的FnOnce/FnMut/Fn
    
    
    // 首先 FnOnce/FnMut/Fn 这三个东西被称为 Trait,
    // 默认情况下它们是交给rust编译器去推理的, 大致的推理原则是:
    //     FnOnce: 当指定这个Trait时, 匿名函数内访问的外部变量必须拥有所有权.
    //     FnMut: 当指定这个Trait时, 匿名函数可以改变外部变量的值.
    //     Fn: 当指定这个Trait时, 匿名函数只能读取(borrow value immutably)变量值.
    
    
    // FnOnce inline way
    // 以获取所有权的方式来获取其所在的环境的所有变量.
    fn anonymous_fnonce() {
        let fn_name = "anonymous_fnonce";
        let mut b = String::from("hello");
        // 通过使用 move 的方式, 把所有权转移进来, rust 编译器
        // 会自动推理出这是一个 FnOnce Trait 匿名函数.
        let pushed_data = move || {
            // 由于所有权转移进来, 因此 b 已经被移除掉.
            // 因此这个匿名函数不可能在被执行第二遍.
            b.push_str(" world!");
            b
        };
        println!("{}: {}", fn_name, pushed_data());     // 这里只能运行一次.
        // println!("{}: {}", fn_name, pushed_data());     // 再次运行会报错.
    }
    
    
    // FnOnce callback way
    fn anonymous_fnonce_callback() {
        let fn_name = "anonymous_fnonce_callback";
        fn calculate<T>(callback: T) -> i32
            where T: FnOnce() -> String
        {
            let data = callback();
            data.len() as i32
        }
    
        let x = " world!";
        let mut y = String::from("hello");
        let result = calculate(|| {
            y.push_str(x);
            y
        });
        println!("{}: {}", fn_name, result);
    }
    
    
    // FnMut inline way
    // 以mutable的方式获取其所在的环境的所有变量.
    fn anonymous_fnmut() {
        let fn_name = "anonymous_fnmut";
        let mut b = String::from("hello");
    
        // rust 自动检测到 pushed_data 这个匿名函数要修改其外部的环境变量.
        // 因此自动推理出 pushed_data 是一个 FnMut 匿名函数.
        let pushed_data = || {
            b.push_str(" world!");
    
            // 由于rust的 mutable 原则是, 只允许一个mut引用, 因此 变量 b 不能
            // 再被其他代码引用, 所以这里要返回更改后的结果.
            b
        };
        let c = pushed_data();
        println!("{}: {}", fn_name, c);
    }
    
    
    // FnMut callback way.
    fn anonymous_fnmut_callback() {
        let fn_name = "anonymous_fnmut_callback";
        fn calculate<T>(mut callback: T)
            where T: FnMut(),
        {
            callback()
        }
    
        let mut b = String::from("hello");
        calculate(|| {
            b.push_str(" world!");
        });
        println!("{}: {}", fn_name, b);
    }
    
    
    // Fn inline way
    // 以immutable的方式获取其所在的环境的所有变量.
    fn anonymous_fn() {
        let fn_name = "anonymous_fn";
        let mut a = String::from("hello");
        let b = String::from(" world!");
        let pushed_data = |x: &mut String| {
            // b 再这里被引用, 但是最后还能被打印, 证明它是被immutable引用.
            x.push_str(&*b);
            println!("{}: {}", fn_name, x);
        };
        pushed_data(&mut a);
         println!("{}: {}", fn_name, b);
    }
    
    
    // Fn callback way
    fn anonymous_fn_callback() {
        let fn_name = "anonymous_fn_callback";
        fn calculate<T>(callback: T)
            where T: Fn()
        {
            callback();
        }
    
        let a = String::from("hello");
        let b = String::from(" world!");
        calculate(|| {
            let joined = format!("{}{}", &*a, &*b);
            println!("{}: {}", fn_name, joined)
        })
    }
    
    
    fn main() {
        anonymous_fnonce();
        anonymous_fnonce_callback();
        anonymous_fnmut();
        anonymous_fnmut_callback();
        anonymous_fn();
        anonymous_fn_callback();
    }
    

    相关文章

      网友评论

          本文标题:rust--匿名函数FnOnce/FnMut/Fn

          本文链接:https://www.haomeiwen.com/subject/pawiwftx.html