3 通用编程概念
3.1 变量
在rust中我们声明一个变量使用let
,例如:
rust
let x: i8 = 1;
rust变量命名规范 使用蛇形命名法
, 如snake_name
,例如:
rust
let my_name: &str = "stephen"
当我们声明了一个字符串变量,但是我想不改变变量名的情况下,重新声明一个数字类型,这时候我们可以使用rust变量变量遮蔽
的特性,例如:
rust
let x: i8 = 1;
let x: &str = "stephen"
当我们不需要更换类型,我们只需要在let
后面加上一个可变mut
符修复,表明当前的变量可以修改,例如:
rust
let mut x: i8 = 1;
3.2 常量
在rust中,我们声明一个常量使用const
关键字,并且命名使用大写蛇形命名法
,例如:
rust
const MY_NAME: &str = "stephen"
我们使用const
声明的变量不能再此修改,否则会编译错误。
3.3 数据类型
3.3.1 标量数据类型
标量分为:
- 整数
- 浮点数
- 布尔值
- 字符串
3.3.1.1 整数
整数分为带符号
和不带符号
的整数,我们使用i
开头表示带正负
号,u
开头表示不带符号(表示正数),例如:
rust
let with_symbol: i32 = -1; // rust默认推导出类型为i32
let without_symbol: u32 = 1;
带符号
和不带符号
的整数的长度类型各有6种,如下:
带符号 | 不带符号 |
---|---|
i8 | u8 |
i16 | i16 |
i32 | u32 |
i64 | u64 |
i128 | u128 |
isize | usize |
其中i8
和u8
分别表示的含义(下面的n,表示n次方),如下:
i8
表示该数字的范围在 -(2n - 1) ~ (2n - 1)之间,也就是-255 ~ 255之间u8
表示该数字的范围在 0 ~ (2n - 1)之间,也就是 0 ~ 255之间
isize
和usize
表示,如果系统的CPU是32位,则表示i32``u32
,如果是64位,则表示i64``i64
3.3.1.2 浮点数
在rust中,我们用f
表示声明的是一个浮点数变量,例如:
rust
let float_number: f64 = 1.0;
浮点数有两种长度类型,f32
和f64
,长度范围和整数一致。
补充:
- 尽量不要长度越界 举个例子,当我们使用
i8
的长度类型,但是我实际的长度为256,这个时候会出现长度越界的情况,实际编码中避免出现这种问题。
3.3.1.3 布尔值
在rust中,我们声明一个布尔值如下:
rust
let booleans: bool = false;
布尔值类型有两种值,true
或者false
3.3.1.4 字符&字符串
在rust,我们使用单引号 ''
声明一个字符:
rust
let character: &str = 'a';
使用双引号 ""
声明一个字符串字面量:
rust
let strings: &str = "stephen"
当我们想声明一个动态长度的字符串怎么生成呢? 这时候我们需要使用String
的new
方法去生成(后面会详细讲到),使用String
生成的字符串,会存储到堆中,并在栈中存储指向堆中的指针 、长度 、容量,例如:
rust
let mut str: String = String::new();
str.push_str("hello")
str.push_str(", world")
3.3.2 复合数据类型
复合类型分为:
- 元组
- 数组
3.3.2.1 元祖
在rust中,我们创建一个元祖,使用()
,元祖可以包含任意的数据类型,例如:
rust
let tuple: (i32, &str) = (1, "stephen")
当我们需要元祖中某个数据项时,我们可以使用索引的方式,例如:
rust
let tuple: (i32, &str) = (1, "stephen");
let first: i32 = tuple.0; // 1
let second: &str = tuple.1; // "stephen"
元祖的类型、长度是固定不变的,长度根据生成时决定,如果尝试修改会编译错误。但是可以使用变量的变量遮蔽
去覆盖则不会报错。例如:
rust
let tuple: (i32, String) = (1, String::new());
let tuple: (i32, i32) = (1, 1); // 正确编译
let mut tuple: (i32, String) = (1, String::new());
tuple: (i32, i32) = (1, 1); // 编译失败
当元祖没有数据时,也叫单元类型
,当我们的函数没有返回时,其实返回的就是单元类型.
rust
let unit_type:() = ();
3.3.2.2 数组
在rust中,我们创建一个数组,使用中括号[]
,数组只能存储相同类型,例如:
rust
let mut arr: [i8; 2] = [1,2];
其中[i8;2]
表示的含义是,第一个是你的数组每一项的类型,第二个表示数据的个数也就是数组的长度;
数组的长度是固定的,不能对其修改,否则会编译错误,例如:
rust
let mut arr: [i8; 2] = [1, 2];
arr.push(2) // 编译出错
那如果我们想创建一个动态长度的数组呢?我们我们可以使用Vec
结构上面的new
方法来生成(后面会详细讲到),或者使用简单的方式,vec![]
,例如:
rust
let mut arr: Vec<i32> = Vec::new(); // 不能初始化数据
arr.push(2) // 编译出错
let arr1: Vec<i32> = vec![1,2,3]; // 可以初始化数据
3.4 注释
在rust中,当我们需要注释的时候我们一般使用//
后续会详细讲到
3.5 if 表达式
在rust中我们一般使用if
来作为条件判断的一个表达式,例如:
rust
let right: bool = true;
if right {
print!("正确")
} else {
print!("错误")
}
注意 我们放到if
表达式中的right
值必须保证是一个布尔值
,否则会编译错误,因为它不会自动转化类型,例如:
rust
let right: i32 = 1;
if right { // 编译错误
print!("正确")
} else {
print!("错误")
}
在rust中,if
会有一个返回值,我们可以使用if
进行条件判断,获取返回值进行后续操作,但是需要保证if
,else if
,else
返回的数据类型相同,,例如:
rust
let return_str: &str = if true { "right" } else { "wrong" };
print("{}", return_str)
并且这里我们可以使用"right"
直接返回该值,非常方便。
这里强调一下,语句和表达式 ,在一个模块中,当我们没有使用;
时,其实可以理解它就是一个表达式,它会返回该值。
3.6 循环
rust中的循环分为3种
- loop
- while
- for
对于loop
的使用,我们可以使用continue
跳过当前循环,使用break
打断当前循环,例如:
rust
let mut index = 0;
loop {
index = index + 1;
if index == 3 {
continue; //跳过
}
println!("{}", index);
if index == 5 {
break; // 打断
}
}
但是每次写break
显得很多余,于是我们可以使用while
循环来优化,例如:
rust
let mut index = 0;
while index < 5 {
index += 1;
if index == 3 {
continue;
}
println!("{}", index);
}
但是当我们循环遍历数组的时候,每次都要去处理这个index
值,很麻烦也不好维护,于是我们使用第三种最常见的循环遍历方法,for
循环,例如:
rust
let arr: Vec<i32> = vec![1, 2, 3, 4, 5];
for i in arr {
if i == 3 {
continue;
}
println!("{}", i)
}
println!("========:========");
for i in 1..6 {
if i == 3 {
continue;
}
println!("{}", i)
}
- 摄氏温度与华氏温度的相互转换。
- 生成一个n阶的斐波那契数列。
- 打印圣诞颂歌The Twelve Days of Christmas的歌词,并利用循环处理其中重复的内容。