函数返回值

在rust中,任何函数都有返回类型,当函数返回时,会返回一个该类型的值。我们先来看看main函数:

  fn main() {
    //statements
  }

之前有说过,函数的返回值类型是在参数列表后,加上箭头和类型来指定的。不过,一般我们看到的main函数的定义并没有这么做。这是因为main函数的返回值是(),在rust中,当一个函数返回()时,可以省略。main函数的完整形式如下:

  fn main() -> () {
    //statements
  }

main函数的返回值类型是(),它是一个特殊的元组——没有元素的元组,称为unit,它表示一个函数没有任何信息需要返回。在Rust Reference的8.1.3 Tuple types中是的描述如下:

For historical reasons and convenience, the tuple type with no elements (()) is often called ‘unit’ or ‘the unit type’.

()类型,其实类似于C/C++、Java、C#中的void类型。

下面来看一个有返回值的例子:

  fn main() {
    let a = 3;
    println!("{}", inc(a));
  }

  fn inc(n: i32) -> i32 {
    n + 1
  }

上面的例子中,函数inc有一个i32类型的参数和返回值,作用是将参数加1返回。需要注意的是inc函数中只有n+1一个表达式,并没有像C/C++或Java、C#等语言有显式地return语句类返回一个值。这是因为,与其他基于语句的语言(如C语言)不同,rust是基于表达式的语言,函数中最后一个表达式的值,默认作为返回值。当然,rust中也有语句,关于rust的语句和表达式,请看下一节

return关键字

rust也有return关键字,不过一般用于提前返回。来看一个简单地例子:

fn main() {
  let a = [1,3,2,5,9,8];
  println!("There is 7 in the array: {}", find(7, &a));
  println!("There is 8 in the array: {}", find(8, &a));
}

fn find(n: i32, a: &[i32]) -> bool {
  for i in a {
    if *i == n {
      return true;
    }
  }
  false
}

上例中,find函数,接受一个i32类型n和一个i32类型的切片(slice)a,返回一个bool值,若n是a的元素,则返回true,否则返回false。可以看到,return关键字,用在for循环的if表达式中,若此时a的元素与n相等,则立刻返回true,剩下的循环不必再进行,否则一直循环检测完整个切片(slice),最后返回false。当然,return语句也可以用在最后返回,像C/C++一样使用:把find函数最后一句false改为return false;(注意分号不可省略)也是可以的,不过这就不是rust的编程风格了。这里需要注意的是,for循环中的i,其类型为&i32,需要使用解引用操作符来变换为i32类型。另外,切片(slice)在这里可以看作是对数组的引用,关于切片与数组的详细解释可以看Rust Referencerustbyexample中的相关内容。

返回多个值

rust的函数不支持多返回值,但是我们可以利用元组来返回多个值,配合rust的模式匹配,使用起来十分灵活。先看例子:

fn main() {
  let (p2,p3) = pow_2_3(789);
  println!("pow 2 of 789 is {}.", p2);
  println!("pow 3 of 789 is {}.", p3);
}

fn pow_2_3(n: i32) -> (i32, i32) {
  (n*n, n*n*n)
}

可以看到,上例中,pow_2_3函数接收一个i32类型的值,返回其二次方和三次方的值,这两个值包装在一个元组中返回。在main函数中,let语句就可以使用模式匹配将函数返回的元组进行解构,将这两个返回值分别赋给p2p3,从而可以得到789二次方的值和三次方的值。

发散函数

发散函数(diverging function)是rust中的一个特性。发散函数不返回,它使用感叹号!作为返回类型表示:

fn main() {
  println!("hello");
  diverging();
  println!("world");
}

fn diverging() -> ! {
  panic!("This function will never return");
}

We call such functions "diverging" because they never return a value to the caller. Every control path in a diverging function must end with a panic!() or a call to another diverging function on every control path. The ! annotation does not denote a type.

Last updated