rust从入门到放弃(八):闭包

在第三篇文章介绍了函数,其实还有另外一种特殊的函数,叫做闭包。闭包在其他语言里面也非常常见,闭包最大的特点就是可以获取上下文信息,并且返回一个函数。

rust从入门到放弃(八):闭包

我们先看一下rust 里面一个简单闭包使用。

fn main() {
    let add = |a , b|->i32 {return a + b;};
    let x = add(1,2);
    println!("result is {}", x);
}

通过 | | 里面放参数,然后函数体实现在{}(如果只有一行的话,{} 也可以省略) 里面。感觉就是省略了fn 关键字并且参数从小括号变成了 | | 。但闭包的功能远不止如此,我们来看一个简单变量捕获。

fn main() {
    let x = 1_i32;
    let add_x = | a | x + a;
    let result1 = add_x( 5 );
    let result2 = add_x( 6 );
    println!("result is {} {}", result1,result2);// 6 7
}

上面的闭包 获取了外部变量 x ,然后针对输入的参数加 1 。这里是不是体现了闭包和函数的区别了。这里把 x 放到闭包里面去使用,这里有三种方式放到闭包里面:所有权、不可变借用、可变借用。

struct T(i32);  //定义类型T
fn by_value(_: T) {} //by_value 参数是 T 所有权
fn by_mut(_: &mut T) {} //by_mut 参数是T 的可变借用
fn by_ref(_: &T) {} //by_ref 参数是T 的不可变借用

fn main() {
    let x: T = T(1);
    let y: T = T(2);
    let mut z: T = T(3);
  
    let closure = || {
        by_value(x); //捕获所有权
        by_ref(&y); // 捕获不可变借用
        by_mut(&mut z); //捕获可变借用
     }; 

    closure(); 
}

rust 在编译的时候会判断闭包内捕获变量的使用方式原则上,尽可能先选择&T类型,其次 选择&mut T类型,最后选择T类型(所有权),尽可能减少对外部 T 的影响。但这里存在一个问题,我们看下面一个例子

fn make_adder(x: i32) -> Box i32> {
    Box::new(|y| x + y)
}
fn main() {
    let f = make_adder(3);
    println!("{}", f(1));
    println!("{}", f(10));
}

按照上面的说法,这里的 x 会通过 &T 的方式被闭包捕获,但当 make_adder 函数返回的时候 x 的生命周期就结束了,那么针对x 的借用自然也会失效,编译的时候报错非常详细,提示闭包生命周期大于 x ,并且告诉你应该使用move将所有权转移到闭包里面。

rust从入门到放弃(八):闭包

这里的move 就是之前介绍所有权里面赋值的move,通过move 关键字将 x 的所有权转移到闭包里面,这样x 的生命周期就可以和闭包保持一致了。我们将函数修改成

fn make_adder(x: i32) -> Box i32> {
    Box::new(move |y| x + y)
}

就可以正常运行了。

展开阅读全文

页面更新:2024-02-28

标签:篇文章   赋值   上下文   括号   变量   所有权   生命周期   函数   入门   例子   说法   关键字   参数   类型   简单   方式   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top