函数与方法
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();
}