本篇文章包含的内容
- 1 变量与常量
- 2 类型
- 2.1 标量类型
- 2.2 复合类型
- 3 函数
- 4 控制流
- 4.1 分支
- 4.2 循环
1 变量与常量
在Rust中,使用let
关键字声明一个变量,变量默认是不可变的。如果要声明可变变量,需要使用mut
关键字将其声明为可变变量。
let x = 1;
x = 2; // 默认不可变,非法
let x = 2; // shadow,合法let mut y = 1;
y = 2;
声明常量需要使用const
关键字,并且在声明时必须指明类型。它甚至可以声明在全局部位,命名需要满足一定的规则:字母全部大写,单词之间用下划线隔开。
const MAX_POINT : u32 = 100_000;
常量一定是不可变的,所以不需要mut
关键字声明,但是它与默认不可变的let
声明的变量有区别。它的赋值结果只能是常量表达式,不能是函数的返回值或者运行时才可以获得的值。
shadowing(隐藏)是Rust的一个重要特性,它允许新声明的变量的变量名替代旧变量。这在很大程度上提高了程序的可读性。被shadow前后的变量类型可以不同。
let spaces = " "; // str
let spaces = spaces.len(); // usize,这里返回 4
2 类型
2.1 标量类型
Rust中有四种标量类型(老四样):
- 整数:默认
i32
; - 浮点:默认
f64
; - 布尔:只有两个值,
true
和false
,占一个字节。 - 字符:Unicode标量值,占用4个字节,可以表示中日韩字符,emoji表情等。
整数类型具体可由下表表示。其中isize
和usize
由操作系统决定,如果操作系统是64位,则isize
相当于i64
,usize
相当于u64
。
整数的表示与C/C++类似,甚至可以添加下划线以提高可读性。例如10_0000
、0xA0
、0b1100_0011
、甚至可以表示为byte类型(u8
only):b'A'
。除了byte类型外,其他整数都可以使用类型后缀,例如57u8
。如果整数溢出,Rust仅会在debug编译模式下panic(恐慌),而在release版本中程序不会panic。
2.2 复合类型
Rust语言中有两种基础的复合类型,即元组(Tuple)和数组。元组用小括号表示,数组用中括号表示。元组中的每一个元素可以是不同类型,而数组中的所有元素都必须是同一种类型。无论是元组还是数组,都需要显式声明他们的类型。
下面是一个使用元组的例子,可以临时声明一个新的元组,例如(x, y, z)
来结构获取旧元组中的每一个成员(Rust会自动推断x
、y
、z
的类型)。
fn main() {let tup : (i32, i64, u8) = (1, 2, 3);let (x, y, z) = tup; // destructureprintln!("{}, {}, {}", x, y, z);println!("{}, {}, {}", tup.0, tup.1, tup.2)
}
使用下面的方法定义一个数组,可以显式地制定数组元素的类型,也可以让Rust编译器自动推断所需的数组类型。如果访问的数组索引超出了数组的范围,编译可能不会报错,但是运行时会导致程序panic。
fn main() {let a = [1, 2, 3, 4 , 5];let b: [i32; 5] = [1, 2, 3, 4, 5];let mouths = ["January","February","March","April","May","June","July","August","September","October","November","December"];let arr = [1; 3]; // let arr = [1, 1, 1];println!("{} {}", a[0], b[1]);
}
如果想让数据存放在stack(栈)内存而不是heap(堆)内存上,或者想要保证有固定数量的元素,则可以使用数组。数组是Stack上分配的单个块的内存。数组是定长的,而与之对应可变长度的数组称为Vector(向量)。如果在实际编程中不知道需要使用数组还是Vector,那么一般都需要使用Vector。
3 函数
Rust函数的命名规范采用snake_case规范,即全部小写,单词之间用下划线分开。Rust中的函数定义顺序无需尊循C/C++的习惯,即函数必须先声明再使用,在Rust中,可以将函数的定义放在函数使用之后。函数参数的类型必须指明。
fn main() {another_func(3);
}fn another_func(num: i32) {println!("Another function!");println!("the num is {}", num)
}
Rust是一个基于表达式的语言。任何一个函数体(语句块,由花括号括起)都由一系列语句组成,可选地,可以由一个表达式结束,函数的返回值就是表达式的值(表达式会产生一个计算值)。
与表达式对应的概念称为语句,一个语句相当于一个命令,语句没有返回值(它返回一个空的Tuple)。函数的定义也是一个语句,所以它不能当作值赋值给变量(废话),这一点和C/C++有很大不同(笔者认为相当于修复了C/C++的一个bug?)。函数的定义是语句,但是调用函数(宏)是一个表达式。
let x = (let y = 6); // 非法let y = {let x = 1;x + 2 // 不能加分号
};println!("the value of y is {}", y); // 3
对于需要返回值的函数,在->
符号后声明函数返回值的类型,但是不能为返回值命名。在Rust中,函数的返回值就是函数最后一个表达式的值,如果需要提前返回,则可以使用 return
关键字,并指定一个值。
fn main() {let x = add_five(4);println!("{}", x); // 9
}fn add_five(num: i32) -> i32 {num + 5// return num + 5;
}
4 控制流
4.1 分支
if
表达式后需要添加一个条件,条件必须是bool类型(它不能是一个语句,这一点也与C/C++不同),与if相关联的代码称为分支(arm)。当程序中出现多个else if
,则建议只用match
语句重构代码。
fn main() {let x = 3;if x % 2 == 0 {println!("x can be devived by 2");} else if x % 3 == 0 {println!("x can be devived by 3");} else if x % 4 == 0 {println!("x can be devived by 4")}
}
if
是一个表达式,所以它可以放在赋值号的右边。实现类似 ? : ;
的效果。需要特别注意的是,if
和else
后程序块的返回值的类型必须相同。
let condition = true;let number = if condition { 5 } else { 6 }; // 5
4.2 循环
Rust中有三种循环:loop
、while
和for
。其使用方法与C/C++和Python比较类似,但是Rust也提供了一些其他的语法糖。
loop
表达式中可以使用break
语句打断循环,并且break
语句后可以添加表达式的值来指定loop
表达式的返回值:
fn main() {let mut counter = 0;let result = loop {counter += 1;if counter == 10 {break counter * 2;}};println!("result: {}", result); // 20
}
while
循环使用较为简单,这里不赘述。
遍历集合元素一般使用for
。Rust中同样存在迭代器的概念。注意,下面的例子中迭代器返回的是数组a
的引用,如果直接写for element in a
,则element
将会被推断为i32类型,而不是&i32
:
fn main() {let a = [1, 2, 3, 4, 5];for element in a.iter() {println!("the value is {}", element);}
}
如果需要代码执行确定的次数,可以使用标准库提供的Range
。Range
可以通过开始数字和结束数字生成一个范围,但不包含结束数字。可以使用rev()
方法获得反转的Range
。
fn main() {for number in (1..4).rev() {println!("{}!", number);}println!("LIFTOFF!");
}
原创笔记,码字不易,欢迎点赞,收藏~ 如有谬误敬请在评论区不吝告知,感激不尽!博主将持续更新有关嵌入式开发、FPGA方面的学习笔记。