1、函数
函数在 Rust 代码中非常普遍。你已经见过语言中最重要的函数之一:main
函数,它是很多程序的入口点。你也见过 fn
关键字,它用来声明新函数。
Rust 代码中的函数和变量名使用 snake case 规范风格,也就是蛇形命名规范,跟python语言是一样的。在 snake case 中,所有字母都是小写并使用下划线分隔单词。这是一个包含函数定义示例的程序:
一个示例如下所示:
fn hello_world() { println!("hello world !") } fn main() { println!("main ......"); hello_world() }
注意,hello_world函数定义在
main
函数 之后;也可以定义在之前。Rust 不关心函数定义所在的位置,只要函数被调用时出现在调用之处可见的作用域内就行。它是静态语言不像其他动态(JavaScript)那样,从上往下执行,那样会找不到对应的函数。
我们可以以下以上方法,看下结果,如下所示:
参数
我们可以定义为拥有 参数(parameters)的函数,参数是特殊变量,是函数签名的一部分。当函数拥有参数(形参)时,可以为这些参数提供具体的值(实参)。技术上讲,这些具体值被称为参数(arguments)。
在上面hello_world函数中,我们增加了一个参数:
fn hello_world(p: i64) { println!("hello world {p}!") } fn main() { println!("main ......"); hello_world(1024) }
运行以上程序,结果如下所示:
在函数签名中,必须 声明每个参数的类型。这是 Rust 设计中一个经过慎重考虑的决定:要求在函数定义中提供对用的类型说明,意味着编译器再也不需要你在代码的其他地方注明类型来指出你的意图。而且,在知道函数需要什么类型后,编译器就能够给出更有用的错误消息。
当定义多个参数时,使用逗号分隔,像这样:
fn hello_world(c: &str,p: i64,) { println!("hello world {c} {p}!") } fn main() { println!("main ......"); hello_world("程序员的", 1024) }
运行一下代码,如下所示:
语句和表达式
函数体由一系列的语句和一个可选的结尾表达式构成。目前为止,我们提到的函数还不包含结尾表达式,不过你已经见过作为语句一部分的表达式。因为 Rust 是一门基于表达式(expression-based)的语言,这是一个需要理解的(不同于其他语言)重要区别。其他语言并没有这样的区别,所以让我们看看语句与表达式有什么区别以及这些区别是如何影响函数体的。
语句(Statements)是执行一些操作但不返回值的指令。 表达式(Expressions)计算并产生一个值。让我们看一些例子。
fn main() { let x = 12345; println!("========={x}========"); }
let x = 12345; 这是一个语句。而等号后面的12345则是一个表达式。
具有返回值的函数
函数可以向调用它的代码返回值。我们并不对返回值命名,但要在箭头(->
)后声明它的类型。在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。使用 return
关键字和指定值,可从函数中提前返回;但大部分函数隐式的返回最后的表达式。
下面是一个具有返回值函数的示例:
fn main() { let y = y(); println!("数字是:{y}") } fn y() -> i32 { 12345 }
运行以上代码,如下所示:
y函数没有参数并定义了返回值类型,不过函数体只有单单一个 12345 也没有分号,因为这是一个表达式,我们想要返回它的值。如果加上分号,就是一个语句,就会报错了。
fn main() { let y = y(); println!("数字是:{y}") } fn y() -> i32 { 12345; }
运行以上代码就会报以下错误:
主要的错误信息,“mismatched types”(类型不匹配),揭示了代码的核心问题。函数 y的定义说明它要返回一个 i32
类型的值,不过语句并不会返回值,使用 ()
表示不返回值。因为不返回值与函数定义相矛盾,从而出现一个错误。在输出中,Rust 提供了一条信息,可能有助于纠正这个错误:它建议删除分号,这会修复这个错误。
2、注释
所有程序员都力求使其代码易于理解,不过有时还需要提供额外的解释。在这种情况下,程序员在源码中留下 注释(comments),编译器会忽略它们,不过阅读代码的人可能觉得有用。
这是一个简单的注释:
// 返回一个数字 fn y() -> i32 { 12345 }
文档注释
Rust 也有特定的用于文档的注释类型,通常被称为 文档注释(documentation comments),它们会生成 HTML 文档。这些 HTML 展示公有 API 文档注释的内容,它们意在让对库感兴趣的程序员理解如何 使用。
以下是一个示例:
/// 返回一个数字(i32) /// 参数:p 类型i32 /// message:...... /// 这是一个返回一个数字的函数 /// fn y(p:i32) -> i32 { p }
多行注释
跟其他语言一样也可以书写多行注释,如下所示:
/** * 这是一个返回整数的方法 * params: p(i32) * return: i32 */ fn y(p:i32) -> i32 { p }
3、控制流
3.1 if 表达式
if
表达式允许根据条件执行不同的代码分支。你提供一个条件并表示 “如果条件满足,运行这段代码;如果条件不满足,不运行这段代码。”
以下是一个示例:
fn main() { let y = 1234; if y > 1024 { println!("满足条件!") } else { println!("不满足条件!") } }
值得注意的是代码中的条件 必须 是 bool
值。如果条件不是 bool
值,我们将得到一个错误。例如,尝试运行以下代码:
fn main() { let y = 1234; if y { println!("满足条件!") } else { println!("不满足条件!") } }
这个错误表明 Rust 期望一个 bool
却得到了一个整数。Rust作为一门静态语言,不会像JavaScript语言那样会进行动态的转换。
3.2 使用esle if 处理多重条件
可以使用if 和 else if 来处理多重条件的判断,以下是一个示例:
fn main() { let y = 1234; if y > 1000 { println!("大于1000!") } else if y > 100 { println!("大于100!") } else if y > 10 { println!("大于10!") } else { println!("小于于10!") } }
3.3 在 let 语句中使用 if
因为 if
是一个表达式,我们可以在 let
语句的右侧使用它,以下是一个示例:
fn main() { let y = true; let res = if y {0} else {1}; println!("res: {res}") }
if
的每个分支的可能的返回值都必须是相同类型,否则会报错,代码改变一下,如下所示:
fn main() { let y = true; let res = if y {0} else {false}; println!("res: {res}") }
3.4 使用循环重复执行
Rust 有三种循环:loop
、while
和 for
。
使用 loop 重复执行代码
loop
关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止。
fn main() { loop { println!("res:") } }
当运行这个程序时,我们会看到连续的反复打印 again!
,直到我们手动停止程序。大部分终端都支持一个快捷键,ctrl-c,来终止一个陷入无限循环的程序。
从循环中返回值
通过loop循环,我们可以通过break语句来中断循环,并返回结果,举一个例子,如下所示:
fn main() { let mut i = 0; let res = loop { i += 1; if i == 5 { break i * i; } }; println!("res: {res}") }
循环标签:在多个循环之间消除歧义
如果存在嵌套循环,break
和 continue
应用于此时最内层的循环。你可以选择在一个循环上指定一个 循环标签(loop label),然后将标签与 break
或 continue
一起使用,使这些关键字应用于已标记的循环而不是最内层的循环。
以下是一个示例:
fn main() { let mut i = 0; 'first: loop { i += 1; loop { if i % 2 == 0 { i += 1; break 'first; } else { break; } } } println!("res: {i}") }
首先定义的可变变量i=0; 进入第一个循环的时候i+1,i的结果为1,进入到第二个循环判断i对2求余是否等于0,结果不等进入else语句块中,在else语句块出现break语句,跳出当前循环,进入到i += 1的位置,所有此时i等于2,然后再次进去第二个循环,i对2求余结果等于0,对i进行加1操作,此时i等于3,然后跳到标签循环的位置,然后往下执行打印结果:"res:3".
while 条件循环
在程序中计算循环的条件也很常见。当条件为 true
,执行循环。当条件不再为 true
,调用 break
停止循环。这个循环类型可以通过组合 loop
、if
、else
和 break
来实现;
以下是一个示例:
fn main() { let mut i = 0; while i < 10 { i += 1; println!("res: {i}") } }
使用for遍历集合
for
循环的安全性和简洁性使得它成为 Rust 中使用最多的循环结构。
下面是一个使用 for
循环的例子:
fn main() { let numbers = [10, 20, 30, 40, 50]; for i in numbers { println!("{i}") } }