Bootstrap

【第八课】Rust中的函数与方法

目录

前言

函数指针

函数当作另一个函数的参数

函数当作另一个函数的返回值

闭包

方法

关联函数

总结


前言

在前面几课中,我们都或多或少的接触到了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中的函数、闭包、方法和关联函数等知识点。和其他的编程语言并没有什么不同。

;