接下来学习变量和常量、基本类型、函数、注释和控制流。我们一个一个详细来看。
变量和常量
我们先看个例子:
rust
fn main() {
let x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
你们说上面的内容运行之后会不会报错,以前端的角色来看let
不就是定义变量的吗? 当然不会报错了。可是这里是Rust
哈哈哈。果断在x=6
这里报错。这是为什么呢?
因为这里的变量引出了一个叫可变性
。变量与可变性,就是说定义了一个变量默认是不可变的,只有加上可变性属性才可以随意该同类型的值。那么我们该如何修改上面的代码呢? 如下:
rust
fn main() {
let x mut = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
就是mut
来标记我们变量的可变性。 当然有变量肯定也就有常量了,那么常量我们怎么定义呢?
Rust
fn main(){
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
}
我们运行之后会有以下内容:

变量的作用域
ini
fn main() {
let x = 5;
let x = x + 1;
{
let x = x * 2;
println!("The value of x in the inner scope is: {x}");
}
println!("The value of x is: {x}");
}
我们看上面这个例子,你觉得控制台会打印出什么?
The value of x in the inner scope is: 12
The value of x is: 6
这次猜对了,和其他编程语言一样是有作用域的。最后附上我们的运行截图:

在Rust中变量有一个区别就是,不能自动转换变量的数据类型。如下所示:
rust
fn main(){
let spaces = " ";
let spaces = spaces.len();
}
运行上面内容就会报错,为什么报错,因为是没有加mut
可变性吗?加上可变性如下:
rust
fn main(){
let mut spaces = " ";
spaces = spaces.len();
}
运行结果还是报错。怎么回事呢?原来是在Rust中不能自动改变变量的数据类型。因为len()
方法是作用在数字上的。字符类型不一样使用肯定报错。
基本类型
由于上面的数据类型不能自动变化的特性,所以我们Rust是静态类型语言。我们再来详细看一下另外一个例子:
rust
fn main(){
let guess: u32 = "42".parse().expect("Not a number!");
println!("The value of guess is: {guess}");
}
上面我们给guess
设置了u32
也就是说无符号的数字类型,假如不添加变量的类型就会报错。接下来我们就仔细讲一下在Rust
中有哪些常见的数据类型:整数、浮点数、布尔值和字符
整数
长度 | 已签名 | 未签名 |
---|---|---|
8位 | i8 |
u8 |
16位 | i16 |
u16 |
32位 | i32 |
u32 |
64位 | i64 |
u64 |
128位 | i128 |
u128 |
依赖于架构 | isize |
usize |
每个带符号变体可以存储从 −(2 n − 1 ) 到 2 n − 1 − 1 (含)之间的数字,其中n 是该变体使用的位数。因此,an
i8
可以存储从 −(2 7 ) 到 2 7 − 1 之间的数字,相当于 −128 到 127。无符号变体可以存储从 0 到 2 n − 1 之间的数字,因此 au8
可以存储从 0 到 2 8 − 1 之间的数字,相当于 0 到 255。
整数溢出
假设你有一个类型的变量u8
,其值可以保存在 0 到 255 之间。如果你尝试将该变量更改为该范围之外的值(例如 256),就会发生整数溢出 ,这可能导致以下两种行为之一。在调试模式下编译时,Rust 会检查整数溢出,如果发生这种情况,程序会在运行时崩溃 。Rust 使用术语 "恐慌"来表示程序因错误退出
当您使用该--release
标志在发布模式下进行编译时,Rust 不会 检查会导致恐慌的整数溢出。相反,如果发生溢出,Rust 会执行二进制补码包装 。简而言之,大于类型可以容纳的最大值的值会"包装"到类型可以容纳的最小值。对于u8
,值 256 变为 0,值 257 变为 1,依此类推。程序不会恐慌,但变量的值可能不是您期望的值。依赖整数溢出的包装行为被视为错误。
浮点数
我们来回看一个浮点数类型的例子,如下所示:
csharp
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
Rust 的浮点类型是f32
和f64
,它们的大小分别为 32 位和 64 位。默认类型是 ,f64
因为在现代 CPU
上,它的速度与CPU
大致相同,f32
但能够实现更高的精度.
接着我们来看一下如何进行数值运算。如下面例子:
rust
fn main() {
// addition
let sum = 5 + 10;
// subtraction
let difference = 95.5 - 4.3;
// multiplication
let product = 4 * 30;
// division
let quotient = 56.7 / 32.2;
let truncated = -5 / 3; // Results in -1
// remainder
let remainder = 43 % 5;
}
这些语句中的每个表达式都使用一个数学运算符,并计算出一个值,然后将其绑定到一个变量
布尔值
布尔类型就两个值,true
和false
.我们来看一个例子:
rust
fn main() {
let t = true;
let f: bool = false; // with explicit type annotation
}
字符
Rust 的char
类型是该语言最原始的字母类型。以下是一些声明char
值的示例:
rust
fn main() {
let c = 'z';
let z: char = 'ℤ'; // with explicit type annotation
let heart_eyed_cat = '😻';
}
复合类型
复合类型可以将多个值组合成一种类型。Rust 有两种原始复合类型:元组和数组。
元组
元组是一种将多个不同类型的值组合成一种复合类型的通用方法。元组的长度是固定的:一旦声明,其大小就无法增加或缩小。 看一个例子:
rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
那么我们如何访问tup
中的一个值呢,如下我们可以结构:
rust
fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {y}");
}
还有没有其他方式呢?如下我们可以通过索引的方式获取:
rust
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
那么我们如何修改元组中的值呢?如下:
rust
fn main() {
let mut x: (i32, i32) = (1, 2);
x.0 = 0;
x.1 += 5;
}
数组
另一种拥有多个值集合的方法是使用数组 。与元组不同,数组的每个元素必须具有相同的类型。与其他一些语言中的数组不同,Rust 中的数组具有固定的长度。 示例
rust
fn main() { let a = [1, 2, 3, 4, 5]; }
可以使用方括号来编写数组的类型,其中包含每个元素的类型、分号以及数组中元素的数量.
rust
let a: [i32; 5] = [1, 2, 3, 4, 5];
这里的 【】中代表的是【类型,数量】。
rust
let a = [3; 5];
上面的是初始化一个数组,指定的数组a
将包含5
所有初始设置为该值的元素 3
。这与书写相同,let a = [3, 3, 3, 3, 3];
但更简洁。这里的 【】中代表的是【初始值,数量】。
这里我们要注意两种中括号的位置的不同,含义也不同
我们如何访问数组数据呢?如下使用索引获取:
rust
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
函数
函数在 Rust 代码中非常普遍。您已经了解了该语言中最重要的函数之一:main
函数,它是许多程序的入口点。您还了解了fn
关键字,它允许您声明新函数。
Rust 代码使用蛇形命名法作为函数和变量名的常规样式,所有字母均小写,并用下划线分隔单词.
rust
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("Another function.");
}
运行上面代码,在命令行会输出什么呢?如下所示:
Hello, world! Another function.
当然我们也可以往函数里面传递参数了,那么如何传递参数呢?我们请看下面代码:
rust
fn main() {
another_function(5);
}
fn another_function(x: i32) {
println!("The value of x is: {x}");
}
运行上面代码我们将可以得到:The value of x is: 5
,这里我们要注意每次在声明函数参数的时候必须要声明参数的类型,像上面的i32
就是x
的参数类型。 那么我们要传入多个参数怎么写呢?别慌我们可以看看下面代码:
rust
fn main() {
print_labeled_measurement(5, 'h');
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("The measurement is: {value}{unit_label}");
}
运行上面代码我们会得到:The measurement is: 5h
.下面我们来讲一个重要的概念: [语句和表达式]
语句和表达式
我们可以自己试着运行下面代码:
rust
fn main() {
let y = { let x = 3; x + 1 };
println!("The value of y is: {y}");
}
注意上面内容我们运行之后控制台会打印:The value of y is: 4
.这是什么原因呢?
原因是let x = 3; x + 1
这里的x+1
没有分号,所以这里并不是一个表达式,而是一个语句。意思就是将x+1
这个语句的结果赋值给y
.
另一种情况,假如我们将x+1
改为x+1;
的话会发生什么?

如上图,报错啦,原因是什么呢?x+1;
是一个语句,不是表达式了就不能够将值赋给y
了。语句不返回任何值。
那么我们就仔细来弄明白什么叫"具有返回值的函数"吧!
具有返回值的函数
rust
fn five() -> i32 {
5
}
fn main() {
let x = five();
println!("The value of x is: {x}");
}
像上面代码中的内容,在函数后面加->
和其返回值类型,就可以认定是有返回值的函数。运行上面代码我们会得到:The value of x is: 5
.
我们再来看一个例子:
rust
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1
}
运行上面代码会输出什么内容?会输出The value of x is: 6
,因为plus_one
函数是个表达式不是语句,假如在x + 1
后面加上分号,将会报错,因为加上分号就变成了语句,然而语句不返回任何内容。所以就会报错!
注释
Rust
中的注释也很简单,下面看几种常见的注释方式:
注释方式一
rust
// 这里是我们的单行注释
// 这里是
// 我们多
// 行注释
/*
这里是
我们多
行注释
*/
上面就是在Rust
的注释了,单行和多行注释,都可以用在语句上方、下方或者语句后面的。
控制流
控制流也就是我们的流程控制
类似在javascript
中的if
和else
或switch
等,我们来看一下在Rust
中如何来使用流程控制吧!
rust
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
上面代码我们定义了一个变量number
,然后去用if
判断。可以看出在Rust
中的流程控制也是用if ...else...
.运行之后返回:condition was true
,假如我们将上面number
改为7,就会打印另外一句话了。
这里我们注意,由于Rust
是静态类型的语言,所以if条件后面跟着的变量类型必须是boolean
,如果不是Boolean就会报错。那么我们如何将数字转换为一个boolean
值呢?如下:
rust
fn main() {
let number = 3;
if number != 0 {
println!("number was something other than zero");
}
}
可以使用运算符,两遍是否相等,如果为真就运行大括号里面的代码,为否就跳过运行。
当然了有的小伙伴可能会说,我有一个学生成绩,按照区间划分等级。你这怎么实现,这里我们绝不使用判断里面套判断。Rust
给我们提供了一个else
分支。如下所示:
rust
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
看完就知道如何使用else分支了吧!
在if中使用let
因为if
是一个表达式,我们可以在语句的右侧使用它let
来将结果赋给变量。之前我们说了什么是表达式什么是语句。我们来看一下如何使用:
rust
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
上面打印出来就是:The value of number is: 5
.这里要注意以下number
的类型一定要统一,也就是说else
两边的内容都要是同一种数据类型,像下面这段代码运行就会报错。
ini
fn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {number}");
}

上图就是我们说的值类型不一致的情况。是不是报错了?
循环
我们接着来看看循环是个怎么回事,很简单循环就是loop
,while
,for
.让我们来看一段代码:
rust
fn main() {
loop {
println!("again!");
}
}
运行上面代码就会在终端一直打印again
,这不是八阿哥,我们按住ctrl+c
停止掉就行了。遇事不慌哈!
那么我们如何在循环中返回值呢?
从循环返回值
rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}
上面代码中的break
就是在循环中返回某个值。所以最后值肯定是20
了。
[循环标签用于消除多个循环之间的歧义]
如果循环内有循环,break
并且continue
此时应用于最内层循环,则可以选择在循环上指定循环标签 break
,然后将其与或 一起使用continue
,以指定这些关键字应用于带标签的循环,而不是最内层循环。循环标签必须以单引号开头。
rust
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
]
rust
fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}
这里的while
和 javascript
的差不多,不做过多讲解啦!
for循环遍历
ini
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}
我们在循环这块比较常用的还是for
循环!
好了,感谢大家观看,有缘再见!