每个 Rust 程序都有函数,至少有一个 main 函数:

fn main() {}

这可能是最简单的函数声明了,fn 用于声明函数,紧跟着的是函数名称,然后是小括号(如果有参数,就写在小括号中)和大括号,大括号中的内容是函数的主体部分。一个带有参数的例子:

fn print_number(x: i32) {
    println!("x is: {}", x);
}

上面定义了一个打印 i32 整型数字的函数,那么怎么使用这个函数呢,看下面完整的例子:

fnmain() {
    print_number(5);
}

fnprint_number(x: i32) {
    println!("x is: {}", x);
}

如你所见,函数的参数用法和 let 声明变量很像,在冒号后面添加参数的类型,但是函数的参数必须声明参数类型,否则编译时会报错。

下面是一个计算两数相加的例子:

fnmain() {
    print_sum(5, 6);
}

fnprint_sum(x: i32, y: i32) {
    println!("sum is: {}", x+y);
}

多个参数通过逗号隔开。

在 Rust 中,只返回一个值的函数,可以用一个箭头来表示:

fnadd_one(x: i32) -> i32 {
    x+1
}

箭头是一个减号和一个大于符号组成的,这个函数返回传入参数加一之后的数,如果有多个表达式的话,最后一行的值作为函数的返回值返回,且最后一行代码末尾不能添加分号,否则编译时会报错。这也说明了 Rust 是一个基于表达式的编程语言(expression-based language)。

表达式和语句总是容易被搞混,分不清哪些是语句哪些是表达式。表达式通常返回一个值,而语句不返回值。Rust 中有两种语句,声明语句和表达式语句。其他的都是表达式。

有的编程语言中,变量绑定是一个表达式,而不是语句,因此变量绑定会返回一个值,于是可以这样写变量绑定:

x = y = 5

因为 y = 5 返回了一个值(值为 5),所以 x 能获得 5 这个值。但是在 Rust 中,使用 let 绑定变量不会返回值,所以像下面这样的用法,编译时会报错:

let x = (let y = 5 ); // expected identifier, found keyword let

编译器告诉我们,let x = 后面应该是一个表达式,而 let y = 5 却是一个不会返回值的语句。

值得注意的是,赋值(y=5)虽然是一个表达式,但是它返回的值并没有什么用。不像其他语言,表达式 y = 5 在 Rust 中并不会返回值 5,而是返回值()(一个空的元组)。如:

let mut y = 5;

let x = (y = 6);  // x has the value (), not 6

Rust 中的第二个语句是表达式语句。它的作用是把任何表达式转换为语句。在实践中,Rust 语法预期一条语句后面跟随另一条语句,也就是 Rust 中使用分号(;)分割的表达式,Rust 就会看起来和其他语言一样要求你在每行末尾加上分号,你也会看到几乎每行 Rust 代码的行末都有分号。再来看看这个代码:

fnadd_one(x: i32) -> i32 {
    x+1
}

这个函数要求返回一个 i32 类型的数字,但是,如果行末有分号,就会返回 (),Rust 知道() 可能并不是我们想要的值,所以会报错,并提示我们去掉这个分号。

在函数中,我们也可以提前返回值,如:

fnfoo(x: i32) ->i32 {
    return x;

    // we never run this code!x+1
}

使用 return 关键词,可以返回想要的值,而 return 后面的代码都不会再执行了。当然,最后一行代码也可以加上 return,但是并不推荐这么做,比如:

fnfoo(x: i32) ->i32 {
    return x + 1;
}

还有没有返回值的函数,散函数(Diverging functions,不知道翻译得对不对):

fndiverges() -> ! {
    panic!("This function never returns!");
}

panic! 是一个宏,和 println! 类似,不同的是,panic! 会使当前线程崩溃,而终止当前线程。因为 panic! 会是使当前线程崩溃,所以这个函数才没有返回值,函数还没返回线程就被终止掉了。

如果在 main 函数中调用上面的函数,并运行,会得到如下输出:

thread ‘

’ panicked at ‘This function never returns!’, hello.rs:2 我们还可以创建绑定函数的变量,如:

let f: fn(i32) -> i32;

这里 f 变量的绑定指向一个函数,这个函数接收一个 i32 类型的参数,并返回一个 i32 类型的值。比如:

fn plus_one(i: i32) -> i32 {
    i + 1
}

// without type inference
let f: fn(i32) -> i32 = plus_one;

// with type inference
let f = plus_one;

然后,我们可以直接调用 f 这个函数:

let six = f(5);

参考链接:https://doc.rust-lang.org/stable/book/functions.html