前言
本文主要梳理Rust函数相关的知识点。
定义
- Rust的函数使用关键字fn开头
- 函数返回 可以使用return语句,也可以使用表达式。
- Rust 代码中的函数和变量名使用 snake case 规范风格。在 snake case 中,所有字母都是小写并使用下划线分隔单词。
fn main() { println!("Hello, world!"); another_function(); } fn another_function() { println!("Another function."); }
- Rust 中的函数定义以
fn
开始并在函数名后跟一对圆括号。大括号告诉编译器哪里是函数体的开始和结尾。 - 上例中,another_function的定义处在调用点之后。Rust 不关心函数定义于何处,只要定义了就行。
- 函数可以拥有参数(parameters),是函数签名的一部分;当函数拥有参数(形参)时,可以为这些参数提供具体的值(实参)。技术上讲,这些具体值被称为参数(arguments)。实际交流中不用这么麻烦,统称参数。
- 在函数签名中,必须 声明每个参数的类型。这是 Rust 设计中一个经过慎重考虑的决定。
- 函数可以有返回值。返回值不用命名,但要在箭头(
->
)后声明它的类型。在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。使用return
关键字和指定值,可从函数中提前返回;但大部分函数隐式的返回最后的表达式。以下是一个示例:fn five() -> i32 { 5 } fn main() { let x = five(); println!("The value of x is: {}", x); }
-
函数也可以不写返回类型,在这种情况下,编译器会认为返回类型 是unit()。
-
函数也可以赋值给变量,然后调用这个变量。如下示例。
fn add1(t : (i32,i32)) -> i32 { t.0 + t.1 } fn add2((x,y) : (i32,i32)) -> i32 { x + y } fn main() { let p = (1, 3); // func 是一个局部变量 let func = add2; // func 可以被当成普通函数一样被调用 println!("evaluation output {}", func(p)); }
-
在Rust中,每一个函数都具有自己单独的类型,但是这个类型可以转换到fn类型函数。示例如下。不过,在参数、 返回值类型不同的情况下是不能作类型转换的。
fn add1(t : (i32,i32)) -> i32 { t.0 + t.1 } fn add2((x,y) : (i32,i32)) -> i32 { x + y } fn main() { // 先让 func 指向 add1 let mut func = add1; // 再重新赋值,让 func 指向 add2 func = add2; //直接赋值,编译会报错。 } //修正方式如下 // 写法一,用 as 类型转换 let mut func = add1 as fn((i32,i32))->i32; // 写法二,用显式类型标记 let mut func : fn((i32,i32))->i32 = add1;
-
Rust的函数体内也允许定义其他item,包括 静态变量、常量、函数、trait、类型、模块等。
发散函数
- Rust支持一种特殊的发散函数(Diverging functions),它的返回类 型是感叹号!。发散类型的最大特点就是,它可以被转换为任意一个类型。
fn diverges() -> ! { panic!("This function never returns!"); } //发散函数可以被转换成任意类型 let x : i32 = diverges(); let y : String = diverges();
-
在Rust中,有这些情况永远不会返回,它们的类型就是!,它们是:1,panic!以及基于它实现的各种函数/宏,比如unimplemented!、 unreachable!;2,无限循环loop{}; ·3,进程退出函数std::process::exit以及类似的libc中的exec一类函数。
main函数
直接上个示例。
fn main() {
for arg in std::env::args() {
println!("Arg: {}", arg);
}
std::process::exit(0);
}
此前,Rust的main函数只支持无参数、无返回值类型的声明方式。后来Rust设计组扩展了main函数的签名, 使它变成了一个泛型函数,这个函数的返回类型可以是任何一个满足 Terminationtrait约束的类型,其中()、bool、Result都是满足这个约束 的,它们都可以作为main函数的返回类型。
const fn函数
- 函数可以用const关键字修饰,这样的函数可以在编译阶段被编译器 执行,返回值也被视为编译期常量。
函数的递归调用
- “当前版本的Rust暂时还不支持尾递归优化,因此如果递归调 用层次太多的话,是有可能撑爆栈空间的” 。
注:后续查证一下看rust的当前版是否之尾递归优化。列为TODO。