目录
前言
在前面几课中,我们都或多或少的接触到了rust中的函数,rust中的函数和其他语言的并没有什么不同,简单的语法不在这篇文章中赘述,我们聊一聊函数式编程语言中的函数,在函数式编程中,例如Scala,函数是一等公民,函数可以被当作参数和返回值。
函数指针
函数指针是指向函数的指针(存储了函数的地址)
听起来像是废话,我们通过代码来看看
fn main() {
let a: fn(&str) -> usize = get_length;
let a_len = a("hello");
}
fn get_length(x: &str) -> usize {
x.len()
}
上面代码中我们定义了一个普通的函数,在main函数中,我们使用a接收了函数名,可以注意看下变量a的类型,这就是函数类型,变量a就是函数指针。我们通过a去调用函数和通过get_length去调用函数取得的效果是一样的。
函数当作另一个函数的参数
fn main() {
let f: fn(&str) -> usize = get_length;
let res = get_length_plus(f, "hello-rust");
}
fn get_length(x: &str) -> usize {
x.len()
}
fn get_length_plus(f: fn(&str) -> usize, other: &str) -> usize {
let len = f(other);
len
}
上面的代码中,定义了2个函数,其中get_lengrh_plus函数的入参是一个函数类型,意味着满足该类型的函数都可以传递进来。
函数当作另一个函数的返回值
fn main() {
let ff: fn(i32, i32) -> i32 = get_function("add");
let res: i32 = ff(1, 2);
println!("res = {}", res);
}
fn get_function(op: &str) -> fn(i32, i32) -> i32 {
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn sub(a: i32, b: i32) -> i32 {
a - b
}
fn default(a: i32, b: i32) -> i32 {
0
}
match op {
"add" => add,
"sub" => sub,
_ => default,
}
}
在上面代码中,我们将函数作为另一个函数的返回值。
闭包
闭包是匿名函数,先看一下闭包的语法
fn main() {
let f1: fn(&str) -> usize = |x: &str| -> usize { x.len() };
f1("hello");
}
闭包的语法和函数的语法基本一样,只是形参的地方使用双竖线表示。闭包有很多省略规则,但是初学者不建议省略太多,按部就班的来。就好像Scala一样,下划线写的太多,组内的同学都看不懂我的代码,导致我注释写的比代码都长。
闭包还有一个特性就是可以捕捉外部的变量,例如下面的代码,变量y虽然定义在闭包外部,但是闭包中使用了变量y,此时闭包会捕捉y。
fn main() {
let y = 1;
let f2 = |x: i32| { x + y };
println!("f2 res = {}", f2(5));
}
方法
在大部分编程语言中,函数和方法是特别类似的2个东西,例如在java中,方法特指属于某个对象的函数,而静态方法属于某个类的函数。Rust中也一样,结构体的函数称之为方法,不过静态方法在Rust中称为关联函数,名字叫法不用,其实都差不多,可以类比着学习,我们先看看方法。
下面代码中,我们定义了结构体Student,并且使用impl块定义Student的方法,在impl块中定义了2个方法,分别是get_name1和get_name2,需要注意的点是,在方法的形参中分别使用了&self和self:&Self;这两种写法是等价的,self代表的是当前的实例,类似java中的self,而Self指的是当前的结构体类型。
struct Student {
name: String,
age: i32,
}
impl Student {
fn get_name1(self: &Self) {
println!("i am {}, age = {}", self.name, self.age);
}
fn get_name2(&self) {
println!("i am {}, age = {}", self.name, self.age);
}
}
fn main() {
let s1 = Student {
name: String::from("wang"),
age: 24,
};
s1.get_name1();
}
关联函数
关联函数类似Java中的类静态方法,通过类名的方式调用,在rust中叫做关联函数,关联结构体的函数,代码如下,还是在impl块中定义,和方法的区别在于,无需加上self形参,这就代表该函数不再是方法,而是一个关联函数,使用方式为结构体名称::函数名。
fn main() {
let s1 = Student {
name: String::from("wang"),
age: 24,
};
Student::learn();
}
struct Student {
name: String,
age: i32,
}
impl Student {
fn learn() {
println!("learn");
}
}
总结
这一节介绍了Rust中的函数、闭包、方法和关联函数等知识点。和其他的编程语言并没有什么不同。