语句与表达式
rust 的函数体由语句和表达式组成。
fn add_with_extra(x: i32, y: i32) -> i32 {
let x = x + 1; // 语句
let y = y + 5; // 语句
x + y // 表达式
}
语句不返回值,而表达式返回值。
// 和很多常见语言中不一样,比如 let x = y = 6 在 js 可以同时给 x,y 赋值
// 由于 let 是语句,没有返回值,因此不能将 let 语句赋值给其它值
let x = (let y = 8);
表达式会进行求值,然后返回一个值,表达式不能包含分号。常见如下:
fn main {
// 函数调用,没有返回值会隐式地返回一个 ()
hello_world();
// 宏调用,返回同函数
println!("hello world");
// 10 + 6 数学运算表达式
let a = 10 + 6;
// 语句块表达式,赋值给变量
let x = {
let x = 10;
x + 1 // 最后一行是表达式,返回了 x + 1 的值,不能以分号结尾
};
// if 语句块也是一个表达式,类似三元运算符
let z = if x % 2 == 1 { "odd" } else { "even" };
}
函数声明与使用
函数的签名包括:
- fn关键字
- 函数名称:命名规范为 snake_case
- 参数 parameters
- 如果有返回值:函数体前加上
-> 类型 - 返回值可以通过
return返回,或是最后一个表达式
fn main() {
hello_word();
another_function(100, 'h'); // 为函数的形参提供具体值(实参)
// this function takes 2 arguments but 1 argument was supplied
another_function(100);
let a = plus_five(10);
println!("{a}");
}
// 这个定义放 main 之前之后都行,不关心定义的位置
// 只要函数被调用时出现在调用之处可见的作用域内就行
fn hello_word() {
println!("hello word")
}
// 函数签名中,必须显式声明每个参数的类型
fn another_function(x: i32, unit_label: char) {
println!("The value of x is: {x} {unit_label}");
}
// 有返回值,需要在函数体前加上类型
fn plus_five(x:i32) -> i32 {
if x > 10 {
return 100; // 通过 return 返回
}
x + 5 // 最后一个表达式作为返回值
}
// 特殊的返回值
// 显式的声明返回单元类型,其实就是没有返回值
fn zero() -> () {}
// 永不返回的发散函数
fn forever() -> ! {
loop {};
}
流程控制
if else 条件分支
和其他语言的相差不大,if、else、else if
// 括号可加可不加,因为括号也是包含一个表达式
// == 只有全等
if condition1 {
// A...
} else if condition1 {
// B...
} else {}
因为if 是一个表达式,可以在let 语句右侧使用它
let condition = true;
let number = if condition { 5 } else { 6 };
// error[E0308]: `if` and `else` have incompatible types
// 值的类型必须相同
let number = if condition { 5 } else { "six" };
loop 循环
fn main() {
// 一直执行,不会返回值,即发散函数 fn main -> ! {}
loop {
println!("again!");
}
// 如果上面的代码不注释,下面的代码会提示:unreachable statement
// 通过 break 结束循环,通过 continue 结束当前循环
let mut x = 1;
loop {
x += 1;
if x == 2 {
continue; // 不会打印 x = 2
}
println!("x = {x}");
if x > 5 {
println!("end {x}"); // end 6
break;
}
}
// 通过 break 结束循环并返回值
let mut a = 1;
let b = loop {
a += 1;
if a > 9 {
break a * 10;
}
};
println!("{b}") // 100
}
嵌套的 loop,可以通过循环标签进行标记,并通过 break 结束。
fn main() {
// 通过 break 结束循环,通过 continue 结束当前循环
let mut a = 1;
let mut b = 1;
'label1: loop {
a += 1;
'label2: loop {
b += 2;
println!("a = {a} b = {b}");
if a + b == 5 {
b += 1;
println!("b = {b}");
break 'label2;
}
if a + b > 5 {
break 'label1;
}
}
}
}
// a = 2 b = 3
// b = 4
// a = 3 b = 6
while 循环
和其他语言中差不多,while 消除了很多使用 loop、if、else 和 break 时所必须的嵌套。
// 使用 while 循环遍历集合中的元素
fn main() {
let a = [1, 2, 3];
let mut index = 0;
// 如果这里改成4,出现数组访问越界
// thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 3'
while index < 3 {
println!("x = {}", a[index]);
index += 1;
}
}
// x = 1
// x = 2
// x = 3
使用while 如果索引长度或测试条件不正确会导致程序 panic,可以用 for 循环替代。
for 循环
for、in 组合
let a = [1, 2, 3];
for element in a {
println!("a = {element}");
}
Rust 提供了一个非常简洁的方式,用来生成连续的数值,即序列(Range)
1..5:生成从 1 到 4 的连续数字1..=5:生成从 1 到 5 的连续数字'a'..='z': 生成 a 到 z 的字母
序列只允许用于数字或字符类型,原因是:它们可以连续。
fn main() {
// 使用 rev,用来反转 range
for number in (1..4).rev() {
println!("{number}!");
}
// 3 2 1
}