【Rust学习记录】3. 通用编程概念

TwoSix Lv3

变量,可变性,隐藏,常量

这部分的内容基本都在前面了解过了,大致就是一下内容

变量与可变性

Rust 默认变量是不可变的,需要可变的话需要加上 mut 关键字。

隐藏

但没有 mut 的变量也可以进行修改,那就是 shadow 机制(翻译为“隐藏”,其实我不太能接受,因为“隐藏”这个词汇常常涉及到安全隐患,但在 Rust 中并非如此)。我们可以通过再 let 一个同名变量,来修改。

1
2
let x = 4;
let x = 5;

这是可以编译通过的。

通过 shadow 来修改变量,和定义 mut 来修改变量的区别是:shadow 可以修改变量的类型,就和我们猜数游戏的 guess 一样,一开始存字符串,后面存 i32,但不同类型的变量在相互赋值时,是会报错的。

常量

和变量不同的是,常量需要显式声明类型,并且必须用常量表达式来赋值。常量使用 const 关键字声明,而不是 let

1
2
3
4
fn main() {
const MAX_NUM:u32 = 100_000;
println!("The value of MAX_NUM is: {}", MAX_NUM);
}

值得一提的是,Rust 支持在数字中间加个下划线提高可读性

数据类型

Rust 本质还是一个静态语言,需要显示的给出变量的具体类型。不过有不少情况,编译器能根据实际情况推导出我们的实际类型罢了,但像 guess 需要作类型转换的时候,还是需要给出具体的类型,上面的常量定义的时候,也需要显示给出变量类型。

定义变量类型的方式也就是上面那样,用冒号加类型

如果要加的时候没有加类型,就会报 cannot infer type for xxxx 意思就是编译器推导不出来类型了,要你给。

标量类型

基本的类型,整型,浮点型,布尔类型,字符型

整型

根据长度命名,有符号为 i8, i16, i32, i64,无符号为 u8, u16, u32, u64

比较特殊的是isize, usize,这两个的长度根据本地环境而定,如果运行的环境是32位系统就是32位,64位系统就是64位。感觉挺牛的。

浮点型

只有两种,f32f64,值得一提的时候,Rust 默认会将浮点型推导为 f64,表述方法是 IEEE-754

布尔型

没什么好说的,:bool

字符型

Rust 用的字符型是用 Unicode 的,而不是 ASCLL,占4个字节;定义和C++一样,字符是单引号,字符串是双引号。

但 Unicode 实际并没有“字符”的概念,所以有点奇怪,书上说是后面会解释

复合类型

基础提供的有 tuplearray

定义方面和 python 像,tuple 用圆括号定义,array 用方括号定义。

底层方面和 c++ 差不多,array 在栈上分配一整片内存,而 tupple 是在堆上分配不一定连续的内存

但两者都是长度不可变的,如果要数组长度可变,可以使用动态数组 vector,这里书上没介绍

tuple 的基本操作:

1
2
3
4
let a:(i32, u32, f32) = (1, 2, 3.0); // 指定类型
let b = (1, 2, 3.0); // 不指定类型,默认推导浮点为 f64
let (x, y, z) = b; // 把 b 拆出来,复制给 x, y, z 三个变量
let c = b.0 //通过下标访问元组

值得一提的是,这里的模式匹配赋值需要带括号 let (x, y, z) = b;

array 的基本操作:

1
2
3
4
let a:[i32; 5] = [3, 3, 3, 3, 3] // 指定类型
let b = [3, 3, 3, 3, 3] //不指定类型
let c = [3; 5] // 用; 重复定义5个3
let first = a[0] // 通过下标访问

Rust 在每次执行数组下标访问的时候,都会作边界检查,如果访问越界的话会抛出异常,然后终止程序运行。而不像 c++ 会自作主张的运行,造成某些难以察觉的 bug

函数

函数怎么定义的,在前面也讲过了,就是 fn,其中传入参数的类型,返回值的类型必须显示定义。

1
2
3
4
// 指定数据类型,返回值类型
fn plus_one(x:i32) -> i32{
x + 1
}

语句和表达式

在Rust里有两个基本的概念,

  1. 语句:执行操作,但不返回值
  2. 表达式:进行计算,返回计算值

let 操作就是一个语句,所以不能进行

1
let a = (let b = 1);

当然也不能写 a = b = 1 这样的语句,因为这些在Rust都是语句,不返回值,不能赋值

let b = 1 中的 1 ,本身就是表达式,返回1, 函数也是个表达式,返回函数的返回值,而我们写的花括号{},本质上也是个表达式,也能返回值,所以上面的语句我们可以写成

1
2
3
4
let a = {
let b = 1;
b + 1
}

花括号就是一个表达式吗,它执行一系列的操作,并返回一个返回值,b+1 也是一个表达式,返回 b+1 的值,值得一提的是,b + 1后面没加分号,如果加了分号,那它就是语句,不是表达式,不会返回值了,这时候编译也会报错。这应该也是之前看到的,Rust 返回值的办法,默认不需要用 return 语句,而是采用表达式的办法。

Rust 默认函数的返回值就是最后一个表达式,但可以使用 return 关键字提前返回

如果函数没有返回值,函数会返回一个空元组;没有指定返回类型,也会默认类型是空元组

若类型不匹配,自然就会编译报错

注释

没什么好说的 //

控制流

if-else表达式

语法和 c++ 几乎一样,但不需要打圆括号,好评

1
2
3
4
5
6
7
8
9
10
11
12
fn main() {
let num = 3;
if num<4 && num < 5 {
println!("num is less than 4 and 5");
}
else if num > 7{
println!("num is greater than 7");
}
else{
println!("num is greater than 4 and less than 7");
}
}

值得一提的是,rust 里的 if 表达式只接受 bool 值,而不会像其他一些语言一样,把不等于 0 的值自动当成 bool 值。也就是在上例不能写成 if num{};

同样,这里if else表达式,而不是语句,也就是说,它可以返回值,所以我们也能用 if 表达式给变量赋值。但同时需要注意类型问题,两个分支不同类型的赋值,还是会编译报错

1
2
3
4
5
fn main() {
let condition = true;
let num = if condition { 5 } else { 6 };
println!("The value of num is: {}", num);
}

循环

loop循环

前面已经介绍过 loop循环表达式了,就是相当于 while true,值得一提的是,表达式,对,loop 也是一个表达式,可以通过 break 返回值。没错,在 Rust 里 break 居然可以返回值

1
2
3
4
5
6
7
fn main() {
let a = loop{
let num = 1;
break num*5;
};
println!("The value of a is: {}", a);
}

while 循环

很常规的循环,但while 就不能用来返回值了,break 不能带数值。

1
2
3
4
5
6
7
fn main() {
let mut num = 0;
while num<=5 {
num += 1;
println!("The value of num is: {}", num);
};
}

for 循环

Rust 里的 for 循环和python差不多,是通过迭代器来进行循环的,这在遍历像数组一样的结构时比较舒服,主要是1. 不会有越界的危险 2. 不需要每次执行过后作一次条件判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
let a = [1,2,3,4,5];
// 普通for循环,和python很像
for i in a.iter() {
println!("{}", i);
}
// 需要获取循环次数的时候,也和python一样,使用enumerate
for (idx, val) in a.iter().enumerate() {
println!("idx:{}, val:{}", idx, val);
}
// 循环一个范围的数的时候
let a = [1,2,3,4,5];
for i in 0..4{
println!("{}", a[i]);
}
// 也可以逆序遍历
for i in (0..4).rev(){
println!("{}", a[i]);
}
}

0..4 确实有点惊到我,抽象程度还挺高。


至此,第三章基本概念结束!这章里面,虽然基本知识很多,但也有不少Rust独特之处,挺惊喜的,可以看到很多地方有些和 python 的相似程度,在保证和 c++ 差不多效率的情况下,在一些语法简洁方面向python看齐(例如自动推导类型),处处都体现着,这确实是一个很现代化的语言。

  • 标题: 【Rust学习记录】3. 通用编程概念
  • 作者: TwoSix
  • 创建于 : 2023-03-25 19:48:36
  • 更新于 : 2024-07-04 23:52:28
  • 链接: https://twosix.page/2023/03/25/【Rust学习记录】3-通用编程概念/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论