Rust 函数

[复制链接]
发表于 2025-6-26 23:35:25 | 显示全部楼层 |阅读模式
Rust 函数


函数

函数在 Rust 代码中非常常见。你已经见过了语言中最紧张的函数之一:main 函数,它是很多步伐的入口点。你还见过 fn 关键字,它答应你声明新的函数。
Rust 代码接纳蛇形命名法(snake case)作为函数和变量名的惯用风格,即所有字母小写,单词之间用下划线分隔。下面是一个包罗函数定义示例的步伐:
文件名:src/main.rs
  1. fn main() {
  2.     println!("Hello, world!");
  3.     another_function();
  4. }
  5. fn another_function() {
  6.     println!("Another function.");
  7. }
复制代码
我们通过输入 fn 后跟函数名和一对括号来定义 Rust 中的函数。花括号告诉编译器函数体的开始和结束位置。
我们可以通过输入函数名和一对括号来调用任何已定义的函数。因为 another_function 已在步伐中定义,以是可以在 main 函数内部调用它。留意,我们在源代码中将 another_function 定义在 main 函数之后;也可以在之前定义。Rust 不关心你在哪里定义函数,只要它们在调用者可见的作用域中定义即可。
让我们新建一个名为 functions 的二进制项目,进一步探索函数。将 another_function 示例放入 src/main.rs 并运行。你应该会看到如下输出:
  1. $ cargo run
  2.    Compiling functions v0.1.0 (file:///projects/functions)
  3.     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s
  4.      Running `target/debug/functions`
  5. Hello, world!
  6. Another function.
复制代码
这些行按照它们在 main 函数中出现的顺序执行。首先打印 “Hello, world!” 消息,然后调用 another_function 并打印其消息。
参数

我们可以定义带有参数的函数,参数是函数签名的一部分的特殊变量。当函数有参数时,你可以为这些参数提供详细的值。严格来说,这些详细的值称为实参(arguments),但在日常交流中,人们通常将参数(parameter)和实参(argument)混用,既指函数定义中的变量,也指调用函数时传入的详细值。
在这个版本的 another_function 中,我们添加了一个参数:
文件名:src/main.rs
  1. fn main() {
  2.     another_function(5);
  3. }
  4. fn another_function(x: i32) {
  5.     println!("The value of x is: {x}");
  6. }
复制代码
尝试运行这个步伐,你应该会得到如下输出:
  1. $ cargo run
  2.    Compiling functions v0.1.0 (file:///projects/functions)
  3.     Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.21s
  4.      Running `target/debug/functions`
  5. The value of x is: 5
复制代码
another_function 的声明有一个名为 x 的参数。x 的范例被指定为 i32。当我们将 5 通报给 another_function 时,println! 宏会将 5 放到格式字符串中包罗 x 的花括号位置。
在函数签名中,必须声明每个参数的范例。这是 Rust 设计中的一个有意决定:要求在函数定义中进行范例注解,意味着编译器险些不必要你在代码的其他地方使用范例注解来推断范例。如果编译器知道函数盼望的范例,也能给出更有资助的错误信息。
定义多个参数时,用逗号分隔参数声明,如下所示:
文件名:src/main.rs
  1. fn main() {
  2.     print_labeled_measurement(5, 'h');
  3. }
  4. fn print_labeled_measurement(value: i32, unit_label: char) {
  5.     println!("The measurement is: {value}{unit_label}");
  6. }
复制代码
这个例子创建了一个名为 print_labeled_measurement 的函数,带有两个参数。第一个参数名为 value,范例为 i32。第二个参数名为 unit_label,范例为 char。然后该函数打印包罗 value 和 unit_label 的文本。
让我们尝试运行这段代码。用上面的例子更换 functions 项目 src/main.rs 文件中的步伐,并使用 cargo run 运行:
  1. $ cargo run
  2.    Compiling functions v0.1.0 (file:///projects/functions)
  3.     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
  4.      Running `target/debug/functions`
  5. The measurement is: 5h
复制代码
因为我们调用函数时,value 的值为 5,unit_label 的值为 ‘h’,以是步伐输出包罗了这些值。
语句与表达式

函数体由一系列语句构成,最后可以以一个表达式末了。到现在为止,我们先容的函数还没有包罗末了的表达式,但你已经见过语句中的表达式。由于 Rust 是一门基于表达式的语言,这一区别很紧张。其他语言没有这样的区分,以是让我们看看语句和表达式是什么,以及它们的区别怎样影响函数体。
语句是执行某些操作但不返回值的指令。
表达式会计算并产生一个值。让我们看一些例子。
实际上,我们已经用过语句和表达式。用 let 关键字创建变量并赋值是一个语句。在示例 3-1 中,let y = 6; 是一个语句。
文件名:src/main.rs
  1. fn main() {
  2.     let y = 6;
  3. }
复制代码
示例 3-1:包罗一个语句的 main 函数声明
函数定义也是语句;整个前面的例子本身就是一个语句。(如下面所示,调用函数不是语句。)
语句不返回值。因此,你不能将 let 语句赋值给另一个变量,如下面的代码尝试做的那样;你会得到一个错误:
文件名:src/main.rs
此代码无法编译!
  1. fn main() {
  2.     let x = (let y = 6);
  3. }
复制代码
运行这个步伐时,你会得到如下错误:
  1. $ cargo run
  2.    Compiling functions v0.1.0 (file:///projects/functions)
  3. error: expected expression, found `let` statement
  4. --> src/main.rs:2:14
  5.   |
  6. 2 |     let x = (let y = 6);
  7.   |              ^^^
  8.   |
  9.   = note: only supported directly in conditions of `if` and `while` expressions
  10. warning: unnecessary parentheses around assigned value
  11. --> src/main.rs:2:13
  12.   |
  13. 2 |     let x = (let y = 6);
  14.   |             ^         ^
  15.   |
  16.   = note: `#[warn(unused_parens)]` on by default
  17. help: remove these parentheses
  18.   |
  19. 2 -     let x = (let y = 6);
  20. 2 +     let x = let y = 6;
  21.   |
  22. warning: `functions` (bin "functions") generated 1 warning
  23. error: could not compile `functions` (bin "functions") due to 1 previous error; 1 warning emitted
复制代码
let y = 6 语句不返回值,以是没有任何东西可以绑定给 x。这与其他语言(如 C 和 Ruby)不同,在那些语言中,赋值会返回赋值的值。你可以写 x = y = 6,让 x 和 y 都等于 6;但在 Rust 中不是这样。
表达式会计算出一个值,并构成你在 Rust 中编写的大部分代码。好比数学运算 5 + 6 是一个表达式,计算结果为 11。表达式可以作为语句的一部分:在示例 3-1 中,语句 let y = 6; 中的 6 就是一个表达式,计算结果为 6。调用函数是表达式。调用宏是表达式。用花括号创建的新作用域块也是表达式,比方:
文件名:src/main.rs
  1. fn main() {
  2.     let y = {
  3.         let x = 3;
  4.         x + 1
  5.     };
  6.     println!("The value of y is: {y}");
  7. }
复制代码
这个表达式:
  1. {
  2.     let x = 3;
  3.     x + 1
  4. }
复制代码
是一个块,在本例中计算结果为 4。该值作为 let 语句的一部分绑定给 y。留意 x + 1 这一行末尾没有分号,这与之前看到的大多数行不同。表达式末尾不加分号。如果你在表达式末尾加上分号,就会把它酿成语句,这样就不会返回值了。在你接下来探索函数返回值和表达式时,请记着这一点。
带返回值的函数

函数可以向调用它们的代码返回值。我们不为返回值命名,但必须在箭头(->)后声明其范例。在 Rust 中,函数的返回值等同于函数体块中最后一个表达式的值。你可以使用 return关键字及指定值提前返回,但大多数函数会隐式返回最后一个表达式。下面是一个返回值的函数示例:
文件名:src/main.rs
  1. fn five() -> i32 {
  2.     5
  3. }
  4. fn main() {
  5.     let x = five();
  6.     println!("The value of x is: {x}");
  7. }
复制代码
在 five 函数中没有函数调用、宏调用,甚至没有 let 语句——只有一个单独的数字 5。这在 Rust 中是完全合法的函数。留意函数的返回范例也被指定为 -> i32。试着运行这段代码,输出应该如下:
  1. $ cargo run
  2.    Compiling functions v0.1.0 (file:///projects/functions)
  3.     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
  4.      Running `target/debug/functions`
  5. The value of x is: 5
复制代码
five 函数中的 5 就是函数的返回值,因此返回范例为 i32。让我们更详细地分析一下。有两个紧张点:首先,let x = five(); 这一行表明我们用函数的返回值初始化变量。因为 five 返回 5,这一行等价于:
  1. let x = 5;
复制代码
其次,five 函数没有参数,并定义了返回值的范例,但函数体只有一个没有分号的 5,因为它是我们想要返回值的表达式。
让我们再看一个例子:
文件名:src/main.rs
  1. fn main() {
  2.     let x = plus_one(5);
  3.     println!("The value of x is: {x}");
  4. }
  5. fn plus_one(x: i32) -> i32 {
  6.     x + 1
  7. }
复制代码
运行这段代码会打印 The value of x is: 6。但如果我们在 x + 1 这一行末尾加上分号,把它从表达式酿成语句,就会报错:
文件名:src/main.rs
此代码无法编译!
  1. fn main() {
  2.     let x = plus_one(5);
  3.     println!("The value of x is: {x}");
  4. }
  5. fn plus_one(x: i32) -> i32 {
  6.     x + 1;
  7. }
复制代码
编译这段代码会产生如下错误:
  1. $ cargo run
  2.    Compiling functions v0.1.0 (file:///projects/functions)
  3. error[E0308]: mismatched types
  4. --> src/main.rs:7:24
  5.   |
  6. 7 | fn plus_one(x: i32) -> i32 {
  7.   |    --------            ^^^ expected `i32`, found `()`
  8.   |    |
  9.   |    implicitly returns `()` as its body has no tail or `return` expression
  10. 8 |     x + 1;
  11.   |          - help: remove this semicolon to return this value
  12. For more information about this error, try `rustc --explain E0308`.
  13. error: could not compile `functions` (bin "functions") due to 1 previous error
复制代码
紧张的错误信息 mismatched types 展现了代码的核心题目。plus_one 函数的定义声明它会返回 i32,但语句不会计算出值,表达为 (),即单元范例。因此没有返回任何值,这与函数定义抵牾,导致报错。在输出中,Rust 提供了大概的修复建议:移除分号,这样就能修复错误。
代码示例

  1. fn main() {
  2.     println!("Hello, world!");
  3.     // another_function();
  4.     another_function(5);
  5.     print_labeled_measurement(5, 'h');
  6.     println!("The value of function give_me_five is: {}", give_me_five());
  7.     let x = plus_one(5);
  8.     println!("The value of x is: {x}");
  9. }
  10. // fn another_function() {
  11. //     println!("Another function.");
  12. // }
  13. fn another_function(x: i32) {
  14.     println!("The value of x is: {x}");
  15. }
  16. fn print_labeled_measurement(value: i32, unit_label: char) {
  17.     println!("The measurement is: {value}{unit_label}");
  18. }
  19. fn give_me_five() -> i32 {
  20.     5
  21. }
  22. fn plus_one(x: i32) -> i32 {
  23.     x + 1
  24. }
复制代码
运行结果:
  1. Hello, world!
  2. The value of x is: 5
  3. The measurement is: 5h
  4. The value of function give_me_five is: 5
  5. The value of x is: 6
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表