序
上一期我们学到了变量与基础数据类型,知道了变量的可变性与变量隐藏,这一期我们来学习一下,函数与控制流,在typescript中我们也有同样的概念,rust也如此,使用起来也大致相同。
函数
Rust 代码中的函数和变量名使用 snake case 规范风格。在 snake case 中,所有字母都是小写并使用下划线分隔单词。上面我们说到了typescript函数,那他们有什么异同?
定义
我们看一个例子:
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("Another function.");
}
-
typescript 我们使用
function
关键字,在rust中我们使用fn
作为关键字 -
Rust 不关心函数定义所在的位置,只要函数被调用时出现在调用之处可见的作用域内就行。(js 会函数提升,差不多类似效果)
参数
rust 在函数签名中,必须 声明每个参数的类型。写typescript的小伙伴都应该清楚这种类型声明方式。
fn main() {
another_function(5);
}
fn another_function(x: i32) {
println!("The value of x is: {x}");
}
- 与typescript不同的是不支持
默认参数
,也不支持可选参数
语句和表达式
Rust 是一门基于表达式(expression-based)的语言,这是一个需要理解的(不同于其他语言)重要区别。其他语言并没有这样的区别,所以让我们看看语句与表达式有什么区别以及这些区别是如何影响函数体的。
使用 let
关键字创建变量并绑定一个值是一个语句
fn main() {
let y = 6;
}
函数定义也是语句,上面整个例子本身就是一个语句。
语句不返回值。因此,不能把 let
语句赋值给另一个变量,所以下面语句会发生错误
fn main() {
let x = (let y = 6);
}
let y = 6
语句并不返回值,所以没有可以绑定到 x
上的值。当然javascript在这里也会报错。
表达式会计算出一个值,并且你将编写的大部分 Rust 代码是由表达式组成的。考虑一个数学运算,比如 5 + 6
,这是一个表达式并计算出值 11
。表达式可以是语句的一部分:在示例中,语句 let y = 6;
中的 6
是一个表达式,它计算出的值是 6
。
函数调用是一个表达式。宏调用是一个表达式。用大括号创建的一个新的块作用域也是一个表达式,例如:
fn main() {
let y = {
let x = 3;
x + 1
};
println!("The value of y is: {y}");
}
注意,这个表达式,是一个代码块,它的值是 4
。这个值作为 let
语句的一部分被绑定到 y
上。
{
let x = 3;
x + 1
}
注意 x+1
这一行在结尾没有分号,与你见过的大部分代码行不同。表达式的结尾没有分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。
这里与javascript有很大的不同,上面的代码在javascript中会抛出错误。在rust的合理的语法
所以得分清楚什么的语句什么是表达式:
语句(Statements)是执行一些操作但不返回值的指令。 表达式(Expressions)计算并产生一个值。
具有返回值的函数
函数可以向调用它的代码返回值。我们并不对返回值命名,但要在箭头(->
)后声明它的类型。
在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。使用 return
关键字和指定值,可从函数中提前返回;但大部分函数隐式的返回最后的表达式。
rust函数 VS typescript函数
- rust函数使用
->
标注返回值类型,typescript:xxx
- rust默认返回最后一个表达式, typescript 默认返回
viod
- 都可以使用
return
提前返回
这样是一个完全合法的函数,因为5
也是一个表达式,默认返回了最后一个表达式。
fn five() -> i32 {
5
}
控制流
控制流与javascript也有一些不同的地方,下面我们来详细介绍一下rust控制流
if 表达式
下面我们来看一个例子:
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
- 在javascript中我们
if 表达式
后需要将条件用()
包裹,rust在这里就不需要了 - rust
if 表达式
条件必须是bool
类型,不可以像javascript一样进行隐私转换
其他的else if 同理,rust也支持,
在 let 语句中使用 if
在rust中 if 是一个表达式,我们可以在 let 语句的右侧使用它,这里有点像javascript中的三元表达式
的效果。
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
if
代码块中的表达式返回一个整数,而 else
代码块中的表达式返回一个字符串。这不可行,因为变量必须只有一个类型。
循环
Rust 有三种循环:loop
、while
和 for
。
我们先介绍一个javascript中没有的循环
loop
loop
关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止。可以使用 break
关键字来告诉程序何时停止循环。
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}
循环标签:在多个循环之间消除歧义
如果存在嵌套循环,break
和 continue
应用于此时最内层的循环。你可以选择在一个循环上指定一个 循环标签:'xxx:
,然后将标签,这里相当于取给loop
取了一个别名。
与 break
或 continue
一起使用,使这些关键字应用于已标记的循环而不是最内层的循环。下面是一个包含两个嵌套循环的示例
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
while
这个循环类型可以通过组合 loop
、if
、else
和 break
来实现;但是由于特别常用,rust内置了。
- 这里和
if
语句一样,条件仅能为bool
类型 - 没有javascript的
()
for
上面我们可以使用 while
结构来遍历集合中的元素,比如数组。
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}
但这个过程很容易出错;如果索引长度或测试条件不正确会导致程序 抛出错误。例如,如果将 a
数组的定义改为包含 4 个元素而忘记了更新条件 while index < 4
,则代码抛出错误。
这也使程序更慢,因为编译器增加了运行时代码来对每次循环进行条件检查,以确定在循环的每次迭代中索引是否在数组的边界内。
作为更简洁的替代方案,可以使用 for
循环来对一个集合的每个元素执行一些代码。
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}
for
循环的安全性和简洁性使得它成为 Rust 中使用最多的循环结构。
这里的for
循环和javascript有较大的区别
- Rust不支持
for ( … ; … ; … )
形式的循环,Rust采用的是for…in
表达式与范围运算符
结合来实现循环 - rust的
for 循环
类似于for of
范围运算符
范围运算符xxx..xxx
形式,是一个左开右闭
区间,能取到左边的值,不能取到右边的值
for i in 1..4 {
println!("{}", i);
}
此段代码输出:1,2,3
结语
从语法上来说javascript与rust在语法上还是有很多区别之处。不过对比起来还是很容易理解。
本文正在参加「金石计划」
原文链接:https://juejin.cn/post/7217750941852287034 作者:阿乐去买菜