基础篇-函数

  • 木头
  • 更新于 2023-02-15 15:18
  • 阅读 1666

参数,语句和表达式,返回值

尽管rust是一门多范式的编程语言,但rust的编程风格是更偏向于函数式的,函数在rust中是一等公民(first-class)。这意味着,函数是可以作为数据在程序中进行传递,如:作为函数的参数。跟C、C++一样,rust程序也有一个唯一的程序入口main函数。rustmain函数形式如下:

fn main() {

}

rust使用 fn 关键字来声明和定义函数,fn关键字隔一个空格后跟函数名,函数名后跟着一个括号,函数参数定义在括号内。rust使用snake_case风格来命名函数,即所有字母小写并使用下划线类分隔单词,如:foo_bar。如果函数有返回值,则在括号后面加上箭头 ->,在箭头后加上返回值的类型。

参数

rust的函数参数声明和一般的变量声明相仿,也是参数名后加冒号,冒号后跟参数类型,不过不需要let关键字。需要注意的是,普通变量声明(let语句)是可以省略变量类型的,而函数参数的声明则不能省略参数类型。 来看一个简单例子:

fn main() {
  say_hi("ruster");
}

fn say_hi(name: &str) {
  println!("Hi, {}", name);
}

尝试运行程序,将会输出如下内容:

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.59s
     Running `target/debug/variables`
Hi, ruster

上例中,say_hi函数拥有一个参数,名为name,类型为&str

语句和表达式

rust是一个基于表达式的语言,不过它也有语句。rust只有两种语句:声明语句和表达式语句,其他的都是表达式。基于表达式是函数式语言的一个重要特征,表达式总是返回值

声明语句

变量声明语句,主要是指let语句,如:

let a = 8;
let b: Vec<f64> = Vec::new();
let (a, c) = ("hi", false);

由于let是语句,所以不能将let语句赋给其他值。如下形式是错误的:

let b = (let a = 8);

当运行这个程序时,会得到如下错误:

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
error: expected expression, found `let` statement
 --> src/main.rs:2:14
  |
2 |     let b = (let a = 8);
  |              ^^^

error: expected expression, found statement (`let`)
 --> src/main.rs:2:14
  |
2 |     let b = (let a = 8);
  |              ^^^^^^^^^
  |
  = note: variable declaration using `let` is a statement

error[E0658]: `let` expressions in this position are unstable
 --> src/main.rs:2:14
  |
2 |     let b = (let a = 8);
  |              ^^^^^^^^^
  |
  = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information

warning: unnecessary parentheses around assigned value
 --> src/main.rs:2:13
  |
2 |     let b = (let a = 8);
  |             ^         ^
  |
  = note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
  |
2 -     let b = (let a = 8);
2 +     let b = let a = 8;
  |

For more information about this error, try `rustc --explain E0658`.
warning: `variables` (bin "variables") generated 1 warning
error: could not compile `variables` due to 3 previous errors; 1 warning emitted

表达式

表达式会计算出一个值,并且你将编写的大部分 Rust 代码是由表达式组成的。函数调用是一个表达式。宏调用是一个表达式。用大括号创建的一个新的块作用域也是一个表达式,例如:

fn main() {
    let y = {
        let x = 3;
        x + 1
    };

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

这个表达式:

{
    let x = 3;
    x + 1
}

是一个代码块,它的值是 4。这个值作为 let 语句的一部分被绑定到 y上。注意 x+1 这一行在结尾没有分号,与你见过的大部分代码行不同。表达式的结尾没有分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。在接下来探索具有返回值的函数和表达式时要谨记这一点。

返回值的函数

函数可以向调用它的代码返回值。我们并不对返回值命名,但要在箭头(->)后声明它的类型。在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。使用 return 关键字和指定值,可从函数中提前返回;但大部分函数隐式的返回最后的表达式。这是一个有返回值的函数的例子:

fn five() -> i32 {
    5
}

fn main() {
    let x = five();

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

five 函数中没有函数调用、宏、甚至没有 let 语句 —— 只有数字 5。这在 Rust中是一个完全有效的函数。注意,也指定了函数返回值的类型,就是-> i32。尝试运行代码;输出应该看起来像这样:

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
     Running `target/debug/variables`
The value of x is: 5

让我们看看另一个例子:

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

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

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

运行代码会产生一个错误,如下:

cargo run
   Compiling variables v0.1.0 (/projects/variables)
error[E0308]: mismatched types
 --> src/main.rs:7:24
  |
7 | fn plus_one(x: i32) -> i32 {
  |    --------            ^^^ expected `i32`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
8 |     x + 1;
  |          - help: remove this semicolon to return this value

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

主要的错误信息,“mismatched types”(类型不匹配),揭示了代码的核心问题。函数 plus_one 的定义说明它要返回一个 i32 类型的值,不过语句并不会返回值,使用单位类型 () 表示不返回值。因为不返回值与函数定义相矛盾,从而出现一个错误。在输出中,Rust 提供了一条信息,可能有助于纠正这个错误:它建议删除分号(推荐)或者改为return x + 1;,这会修复这个错误。

多返回值

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二次方的值和三次方的值。

  • 原创
  • 学分: 6
  • 分类: Rust
  • 标签:
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
127 订阅 31 篇文章

0 条评论

请先 登录 后评论
木头
木头
0xC020...10cf
江湖只有他的大名,没有他的介绍。