Rust function & closure

it2023-02-18  77

文章目录

函数与方法闭包输入函数作为输出参数

函数与方法

struct Point{ x:f64, y:f64, } impl Point{ // 静态方法(static method) fn origin() ->Point { Point{ x:0.0,y:0.0} } fn new(x:f64,y:f64)->Point{ Point{x:x, y:y} } } struct Rectangle{ p1:Point, p2:Point, } impl Rectangle{ // 实例方法(instance method) // area method 求面积 fn area(&self)->f64{ let Point{x:x1,y:y1} = self.p1; let Point{x:x2,y:y2} = self.p2; ((x1 -x2) * (y1 -y2)).abs() } // circumference 求周长 fn circumference(&self) ->f64{ let Point{x:x1,y:y1} = self.p1; let Point{x:x2,y:y2} = self.p2; 2.0*((x1 -x2).abs() + (y1 -y2).abs()) } fn translate(&mut self,x:f64,y:f64){ self.p1.x +=x; self.p1.y +=y; self.p2.x +=x; self.p2.y +=y; } } struct Pair(Box<i32>,Box<i32>); impl Pair{ // 此方法会“消耗” 调用者的资源 fn destroy(self){ let Pair(first,second) = self; println!("Destroying Pair({}, {})", first, second); } } fn main() { let rectangle = Rectangle{ // 静态方法使用双冒号调用 p1:Point::origin(), p2:Point::new(3.0,4.0), }; println!("Rectangle circumference:{}",rectangle.circumference()); println!("Rectangle area:{}",rectangle.area()); let mut square = Rectangle{ p1:Point::origin(), p2:Point::new(1.0,1.0), }; square.translate(1.0,1.0); println!("square area:{}",square.area()); let pair = Pair(Box::new(1),Box::new(2)); pair.destroy(); } // Rectangle circumference:14 // Rectangle area:12 // square area:1 // Destroying Pair(1, 2)

闭包

Rust 中的闭包(closure),也叫做 lambda 表达式或者 lambda,是一类能够捕获周围作用域中变量的函数。

闭包允许变量捕获(capture)灵活地适应使用场合,既可移动(move)又可 借用(borrow)变量。闭包可以通过以下手段捕获变量:

Fn 通过引用: &T

FnMut通过可变引用: &mut T

FnOnce通过值: T

译注:顺序之所以是这样,是因为 : &T 只是获取了不可变的引用, &mut T 则可以改变变量, T 则是拿到了变量的所有权而非借用。

use std::mem; fn main() { let color = "green"; let print = ||println!("color: {}", color); print(); print(); let moveable = Box::new(3); let consume = ||{ println!("moveable: {:?}",moveable); mem::drop(moveable); }; consume(); // 只能运行一次,不可复制类型(在堆上申请空间的数据类型)必须移动(move)到闭包中 let stack = vec![1,2,3,4,5]; let contains = move |needle|stack.contains(needle); println!("向量stack的容量是否包含1:=>{}",contains(&1)); println!("向量stack的容量是否包含6:=>{}",contains(&6)); } // color: green // color: green // moveable: 3 // 向量stack的容量是否包含1:=>true // 向量stack的容量是否包含6:=>false

示例二 以下的示例,将函数(闭包)作为参数传入函数中。

use std::mem; //该函数将闭包作为参数并调用它 fn apply<F>(f:F) where //闭包没有输入值和返回值 F:FnOnce(){ f(); } fn apply_to_3<F>(f:F)->i32 where F: Fn(i32) ->i32{ f(3) } fn main() { let greeting = "hello"; let mut farewell = "goodbye".to_owned(); let diary = ||{ println!("I said {}.",greeting); // `greeting`通过引用捕获,故需要闭包是`Fn` farewell.push_str("!!!"); // 改变了`farewell`,闭包通过可变引用来捕获它,需要`FnMut`。 println!("Then I screamed {}.",farewell); mem::drop(farewell); //手动调用drop,闭包通过值获取`farewell`(包括所有权)。需要`FnOnce` }; apply(diary); let double = |x| {2*x}; println!("3 double: {}",apply_to_3(double)); } // I said hello. // Then I screamed goodbye!!!. // 3 double: 6
输入函数
fn call_me<F:Fn()>(f:F){ f() } fn function(){ println!("I'm a function!!!"); } fn main(){ let closure = ||println!("I am a closure!"); call_me(closure); call_me(function); } // I am a closure! // I'm a function!!!
作为输出参数

目前 Rust 只支持返回具体(非泛型)的类型。 按照定义,匿名的闭包的类型是未知的,所以只有使用 impl Trait 才能返回一个闭包。

必须使用 move 关键字(捕获都是通过值进行),因为在函数退出时,任何通过引用的捕获都被丢弃,防止在闭包中留下无效的引用。

示例(返回闭包(函数))

fn create_fn() ->impl Fn(){ let text = "zhangsan".to_owned(); move||println!("This is a {}",text) } fn create_fnmut()-> impl FnMut(){ let text = "lisi".to_owned(); move||println!("This is a {}",text) } fn main() { let fn_plain = create_fn(); let mut fn_mut = create_fnmut(); fn_plain(); fn_mut(); }
最新回复(0)