03 - Rust函数

03 - Rust函数



前言

函数是编程编程语言中的基本模块,通过对代码块进行封装成函数,实现特定功能。对外仅提供函数名作为接口,方便外部调用。
函数本身就是一种类型,函数类型变量可以作为其他函数的参数或者返回值,也可以赋值给别的变量,还可以直接调用执行。


一、函数定义

Rust 使用fn关键字定义函数。函数的定义使用fn关键字,后跟函数名、参数列表、返回类型和函数体。
函数体包含于{}内,是函数要执行的具体代码。
fn <函数名> ( <参数> ) <函数体> { }
如下函数实例,定义了一个名为another_function的无参、无返回值的函数。

fn main() {
    println!("Hello, world!");
    another_function();
}

fn another_function() {
    println!("Hello, nhooo!");
}

1.1 函数参数

函数参数必须明确指定数据类型,但不能指定默认值。
Rust 中定义函数如果需要具备参数必须声明参数名称和类型。

fn main() {
    another_function(2, 3);
}

fn another_function(x: i32, y: i32) {
    println!("x 的值为 : {}", x);
    println!("y 的值为 : {}", y);
}
/*输出
x 的值为 : 5
y 的值为 : 6
*/

函数参数可以分为可变和不可变参数,默认不可变参数,需要可变操作时,需要加上mut关键字。

fn add(mut x: i32,  y:i32) -> i32 {
    x = x + 1;
    return  x + y;
}

fn main() {
    let x = 5;
    let y = {
        let x = 2;
        x + 1  // 结尾没有分号
    };
    
    let sum = add(x,y);
    println!("{} + {} = {}",x,y,sum);
}

1.2 函数体语句和表达式

main函数:main函数是程序的入口函数,对于可执行文件来说,main函数是必不可少的,对于库函数来说,main函数不是必须的。

函数体: 函数体由一系列语句和一个可选的结尾表达式构成。

结尾没有分号,代表这是一个表达式而非语句,将会自动返回表达式的值,表示式的结尾如果加上分号,就变成了语句,语句没有返回值。
Rust 中可以在一个用 {} 包括的块里编写一个较为复杂的表达式:

fn add(x: i32, y:i32) -> i32 {
    x+y   // 结尾没有分号
}

fn main() {
    let x = 5;
    let y = {
        let x = 2;
        x + 1  // 结尾没有分号
    };
    
    let sum = add(x,y);
    println!("{} + {} = {}",x,y,sum);
}
//5 + 3 = 8

这段程序中包含了一个表达式块:

{
    let x = 3;
    x + 1
};

而且在块中可以使用函数语句,最后一个步骤是表达式,此表达式的结果值是整个表达式块所代表的值。这种表达式块叫做函数体表达式。
注意:x + 1 之后没有分号,否则它将变成一条语句!

这种表达式块是一个合法的函数体。而且在 Rust 中,函数定义可以嵌套:
示例:

fn main() {
    fn five() -> i32 {
        5
    }
    println!("five() 的值为: {}", five());
}

1.3 函数返回值

如果函数需要返回值给调用者,在函数定义时需要明确返回值类型。
使用 -> 数据类型来定义
函数只能有一个返回值,需要返回多个值时,可以使用元组类型。

Rust中每个函数都有返回值,即使没有显示返回值的函数,也会隐式地返回一个单元值()

一般,函数隐式地返回函数体最后一个表达式的值。

上一个嵌套函数示例已经显示了函数的返回值定义方式,
Rust 函数声明返回值类型的方式:在参数声明之后用 -> 来声明函数返回值的类型。
在函数体中,随时都可以以 return 关键字结束函数运行并返回一个类型合适的值。
示例:

fn add(a: i32, b: i32) -> i32 {
	// a + b  //函数体表达式
    return a + b;
}

Rust 不支持自动返回值类型判断!如果没有明确声明函数返回值的类型,函数将被认为是"纯过程",不允许产生返回值,return 后面不能有返回值表达式。这样做的目的是为了让公开的函数能够形成可见的公报。

注意:函数体表达式并不能等同于函数体,它不能使用 return 关键字。

1.4 函数作为参数和返回值

在Rust中,函数可以作为参数传递给其他函数,也可以作为函数的返回值。这种特性可以实现函数的灵活组合和高阶函数的编写。
以下是一个函数作为参数和返回值的示例:

fn add(a: i32, b: i32) ->i32 {
    return a + b;
}

fn mult(a: i32, b: i32) ->i32 {
	return a * b;
}
fn calc(function: fn(i32, i32)->i32, a: i32, b: i32) -> i32 {
	return function(a,b);
}

fn main(){
	let result = calc(add, 100,100);
	println!("result = {}", result);

	let result = calc(mult, 100,200);
	println!("result = {}", result);
}
//result = 200
//result = 20000

在上述示例中,定义了两个简单的函数add和mult,分别用完成两个参数的相加和相乘操作。

然后定义了一个名为calc的函数,它接收一个函数参数function,类型为fn(i32, i32) -> i32,表示接收两个i32类型参数并返回i32类型结果的函数。在函数体中,我们调用了function函数,并传递了a和b作为参数。

在main函数中分别使用add和mult作为calc函数的参数,并打印出计算结果。

1.5 方法

方法和函数类似,都是使用fn关键字定义,可以有参数、返回值、函数体。
结构体的方法必须在结构体的上下文中定义,也就是定义在impl块中。

在impl块中定义的不一定是方法,也有可能是关联函数。

方法要求第一个参数必须是self, 代表调用该方法的结构体实例。

在方法中使用&self能够读取实例中的数据,使用&mut self能够向实例中写入数据。

使用方法替代函数的最大好处在于组织性,将结构体实例的所有行为都一起放入impl块中

关联函数是指在impl块中定义,但是不以self作为参数的函数,与结构体相关联,但是不直接作用于结构体实例,常用作返回一个结构体实例的构造函数。

调用:

在方法内部可以使用self.字段名 来访问结构体的字段
在方法外使用实例名.方法名 调用方法
调用关联函数使用 结构体名::关联函数名
在调用结构体方法时,第一个参数self不需要传递实参,由Rust编译器完成

pub struct Student {
    name :&'static str,
    score : i32,
}

impl Student {
    pub fn new(name : &'static str,socre:i32) ->Self{
		Student{name,socre}
    }
    
    pub fn get_name(&self) -> &str {
		self.name
    }           
}

fn main(){
    let mut student : Student = Student::new("wkk",22);
    println!("{:?}",student);
}

1.6 高阶函数

以函数为参数或者返回值的函数。

函数是一种类型,函数类型的变量可以像其他类型的变量一样使用,可以被直接调用执行,也可以作为其他函数的参数或者返回值。

实现这一切的基础是函数指针,函数指针类型使用fn() 来指定

1.7 函数指针

指向函数的指针,值是函数的地址
声明中必须显示指定函数后指针的类型fn()

fn hello(){
    println!("hello Rust");
}

fn main(){
    let fn_ptr: fn() = hello;
    fn_ptr();
    let other_fn = hello; // 函数hello本身的类型 , other_fn 不是函数指针类型
}
//hello Rust

函数指针和闭包都可以用来表示可调用对象,但它们之间有一些重要的区别。其中一个区别是,闭包可以捕获其周围环境中的变量,而函数指针则不能。
不同于闭包,fn 是一个类型而不是一个 trait,所以直接指定 fn 作为参数而不是声明一个带有 Fn 作为 trait bound 的泛型参数。
函数指针实现了所有三个闭包 trait(Fn、FnMut 和 FnOnce),所以总是可以在调用期望闭包的函数时 传递函数指针作为参数。
倾向于编写使用泛型和闭包 trait 的函数,这样它就能接受函数或闭包作为参数。 一个只期望接受 fn 而不接受闭包的情况的例子是与不存在闭包的外部代码交互时:C 语言的函数可以接受函数作为参数,但 C 语言没有闭包。

函数指针的应用场景:

可以作为参数传递给其他函数,以便在函数内部调用。这在一些高阶函数(higher-order functions)中非常常见,例如 map 和 filter 等。
函数指针还可以用于定义回调函数(callback functions),例如在事件驱动编程(event-driven programming)中。
函数指针还可以存储在数据结构中,以便稍后调用。这在一些算法中非常有用,例如排序算法。

函数指针的优缺点

函数指针的优点之一是它们没有运行时开销。这意味着它们可以在不影响性能的情况下用于表示可调用对象。
但是,函数指针也有一些局限性。例如,它们不能捕获其周围环境中的变量,这使得它们不如闭包灵活。此外,函数指针只能指向那些在编译时已知的函数,这意味着它们不能用于表示匿名函数。


总结

本章学习在Rust中函数的使用方法。包括无参函数、有参函数、函数返回值、函数体语句和表达式、函数作为参数和返回值、方法以及函数指针的用法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值