06.Rust 语言实战笔记 —— 函数

462 阅读4分钟

在函数界,有一个函数只闻其名不闻其声,可以止小孩啼!在程序界只有  hello,world!  可以与之媲美,它就是  add  函数:

fn add(i: i32, j: i32) -> i32 {
   i + j
}

该函数如此简单,但是又是如此的五脏俱全,声明函数的关键字  fn ,函数名  add(),参数  i  和  j,参数类型和返回值类型都是  i32,总之一切那么的普通,但是又那么的自信,直到你看到了下面这张图:

当你看懂了这张图,其实就等于差不多完成了函数章节的学习,但是这么短的章节显然对不起读者老爷们的厚爱,所以我们来展开下。

函数要点

  • 函数名和变量名使用蛇形命名法(snake case),例如  fn add_two() -> {}
  • 函数的位置可以随便放,Rust 不关心我们在哪里定义了函数,只要有定义即可
  • 每个函数参数都需要标注类型

函数参数

Rust 是强类型语言,因此需要你为每一个函数参数都标识出它的具体类型,例如:

fn main() {
    another_function(5, 6.1);
}


fn another_function(x: i32, y: f32) {
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

another_function  函数有两个参数,其中  x  是  i32  类型,y  是  f32  类型,然后在该函数内部,打印出这两个值。这里去掉  x  或者  y  的任何一个的类型,都会报错:

fn main() {
    another_function(5, 6.1);
}


fn another_function(x: i32, y) {
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

错误如下:

   Compiling playground v0.0.1 (/playground)
error: expected one of `:`, `@`, or `|`, found `)`
 --> src/main.rs:5:30
  |
5 | fn another_function(x: i32, y) {
  |                              ^ expected one of `:`, `@`, or `|`
  |
  = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
help: if this is a parameter name, give it a type
  |
5 | fn another_function(x: i32, y: TypeName) {
  |                              ++++++++++
help: if this is a type, explicitly ignore the parameter name
  |
5 | fn another_function(x: i32, _: y) {
  |                             ++


error: could not compile `playground` due to previous error

函数返回

在上一章节语句和表达式中,我们有提到,在 Rust 中函数就是表达式,因此我们可以把函数的返回值直接赋给调用者。

函数的返回值就是函数体最后一条表达式的返回值,当然我们也可以使用  return  提前返回,下面的函数使用最后一条表达式来返回一个值:

fn plus_five(x:i32) -> i32 {
    x + 5
}


fn main() {
    let x = plus_five(5);


    println!("The value of x is: {}", x);

x + 5  是一条表达式,求值后,返回一个值,因为它是函数的最后一行,因此该表达式的值也是函数的返回值。

再来看两个重点:

  1. let x = plus_five(5),说明我们用一个函数的返回值来初始化  x  变量,因此侧面说明了在 Rust 中函数也是表达式,这种写法等同于  let x = 5 + 5;
  2. x + 5  没有分号,因为它是一条表达式,这个在上一节中我们也有详细介绍

再来看一段代码,同时使用  return  和表达式作为返回值:

fn plus_or_minus(x:i32) -> i32 {
    if x > 5 {
        return x - 5
    }


    x + 5
}

fn main() {
    let x = plus_or_minus(5);


    println!("The value of x is: {}", x);

plus_or_minus  函数根据传入  x  的大小来决定是做加法还是减法,若  x > 5  则通过  return  提前返回  x - 5  的值,否则返回  x + 5  的值。

Rust 中的特殊返回类型

无返回值 ()

对于 Rust 新手来说,有些返回类型很难理解,而且如果你想通过百度或者谷歌去搜索,都不好查询,因为这些符号太常见了,根本难以精确搜索到。

例如单元类型  (),是一个零长度的元组。它没啥作用,但是可以用来表达一个函数没有返回值:

  • 函数没有返回值,那么返回一个  ()
  • 通过  ;  结尾的表达式返回一个  ()

例如下面的  report  函数会隐式返回一个  ()

use std::fmt::Debug;

fn report<T: Debug>(item: T) {
  println!("{:?}", item);
}

与上面的函数返回值相同,但是下面的函数显式的返回了  ()

fn clear(text: &mut String) -> () {
  *text = String::from("");
}

在实际编程中,你会经常在错误提示中看到该  ()  的身影出没,假如你的函数需要返回一个  u32  值,但是如果你不幸的以  表达式;  的方式作为函数的最后一行代码,就会报错:

fn add(x:u32,y:u32) -> u32 {
    x + y;
}

错误如下:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:4:24
  |
4 | fn add(x:u32,y:u32) -> u32 {
  |    ---                 ^^^ expected `u32`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
5 |     x + y;
  |          - help: consider removing this semicolon


For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

还记得我们在语句与表达式中讲过的吗?只有表达式能返回值,而  ;  结尾的是语句,在 Rust 中,一定要严格区分表达式语句的区别,这个在其它语言中往往是被忽视的点。

永不返回的函数!

当用  !  作函数返回类型的时候,表示该函数永不返回,特别的,这种语法往往用做会导致程序崩溃的函数:

fn dead_end() -> ! {
  panic!("你已经到了穷途末路,崩溃吧!");
}

下面的函数创建了一个无限循环,该循环永不跳出,因此函数也永不返回:

fn forever() -> ! {
  loop {
    //...
  };
}