Rust 函数

函数(function)使用 fn 关键字来声明。函数的参数需要标注类型,就和变量一样,如果函数返回一个值,返回类型必须在箭头 -> 之后指定。

函数最后的表达式将作为返回值。也可以在函数内使用 return 语句来提前返一个值,甚至可以在循环或 if 内部使用。

让我们使用函数来重写 FizzBuzz 程序吧!

// 和 C/C++ 不一样,Rust 的函数定义位置是没有限制的
fn main() {
    // 我们可以在这里使用函数,后面再定义它
    fizzbuzz_to(100);
}

// 一个返回布尔值的函数
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
    // 边界情况,提前返回
    if rhs == 0 {
        return false;
    }

    // 这是一个表达式,可以不用 `return` 关键字
    lhs % rhs == 0
}

// 一个 “不” 返回值的函数。实际上会返回一个单元类型 `()`。
fn fizzbuzz(n: u32) -> () {
    if is_divisible_by(n, 15) {
        println!("fizzbuzz");
    } else if is_divisible_by(n, 3) {
        println!("fizz");
    } else if is_divisible_by(n, 5) {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}

// 当函数返回 `()` 时,函数签名可以省略返回类型
fn fizzbuzz_to(n: u32) {
    for n in 1..=n {
        fizzbuzz(n);
    }
}

高阶函数

Rust 提供了高阶函数(Higher Order Function, HOF),指那些输入一个或多个函数,并且/或者产生一个更有用的函数的函数。HOF 和惰性迭代器(lazy iterator)给 Rust 带来了函数式(functional)编程的风格。

fn is_odd(n: u32) -> bool {
    n % 2 == 1
}

fn main() {
    println!("Find the sum of all the squared odd numbers under 1000");
    let upper = 1000;

    // 命令式(imperative)的写法
    // 声明累加器变量
    let mut acc = 0;
    // 迭代:0,1, 2, ... 到无穷大
    for n in 0.. {
        // 数字的平方
        let n_squared = n * n;

        if n_squared >= upper {
            // 若大于上限则退出循环
            break;
        } else if is_odd(n_squared) {
            // 如果是奇数就计数
            acc += n_squared;
        }
    }
    println!("imperative style: {}", acc);

    // 函数式的写法
    let sum_of_squared_odd_numbers: u32 =
        (0..).map(|n| n * n)             // 所有自然数取平方
             .take_while(|&n| n < upper) // 取小于上限的
             .filter(|&n| is_odd(n))     // 取奇数
             .fold(0, |sum, i| sum + i); // 最后加起来
    println!("functional style: {}", sum_of_squared_odd_numbers);
}

发散函数

发散函数(diverging function)绝不会返回。 它们使用 ! 标记,这是一个空类型。

#![allow(unused)]
fn main() {
fn foo() -> ! {
    panic!("This call never returns.");
}
}

和所有其他类型相反,这个类型无法实例化,因为此类型可能具有的所有可能值的集合为空。 注意,它与 () 类型不同,后者只有一个可能的值。

如下面例子,虽然返回值中没有信息,但此函数会照常返回。

fn some_fn() {
    ()
}

fn main() {
    let a: () = some_fn();
    println!("This function returns and you can see this line.")
}

下面这个函数相反,这个函数永远不会将控制内容返回给调用者。

#![feature(never_type)]

fn main() {
    let x: ! = panic!("This call never returns.");
    println!("You will never see this line!");
}

虽然这看起来像是一个抽象的概念,但实际上这非常有用且方便。这种类型的主要优点是它可以被转换为任何其他类型,从而可以在需要精确类型的地方使用,例如在 match 匹配分支。 这允许我们编写如下代码:

fn main() {
    fn sum_odd_numbers(up_to: u32) -> u32 {
        let mut acc = 0;
        for i in 0..up_to {
            // 注意这个 match 表达式的返回值必须为 u32,
            // 因为 “addition” 变量是这个类型。
            let addition: u32 = match i%2 == 1 {
                // “i” 变量的类型为 u32,这毫无问题。
                true => i,
                // 另一方面,“continue” 表达式不返回 u32,但它仍然没有问题,
                // 因为它永远不会返回,因此不会违反匹配表达式的类型要求。
                false => continue,
            };
            acc += addition;
        }
        acc
    }
    println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9));
}

这也是永远循环(如 loop {})的函数(如网络服务器)或终止进程的函数(如 exit())的返回类型。