Rust 基础整理
数值类型
- 使用 0b/0o/0x 来表示 2/8/16 进制数
- 数值类型有如下: i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, iszie, usize, 其中 iszie 和 usize 分别根据 CPU 的字长不同可以是 32 bit 或 64 bit.
- 不同类型转换使用
try_into
, 也可以使用as
PartialEq
和Eq
的区别:- 如果我们想比较某个类型的两个值 x 和 y 是否相等(不等),例如:x == y (x != y),那么我们就必须为类型实现
PartialEq
. PartialEq
可使用#[derive]
来交由编译器实现,当一个 struct 在进行相等比较时,会对其中每一个字段进行比较;如果遇到枚举时,还会对枚举所拥有的数据进行比较。- 我们也可以自己实现
PartialEq
,实现时只需要实现判断是否相等的函数fn eq(&self, other: &Self) -> bool
,Rust 会自动提供fn ne(&self, other: &Self) -> bool
. - 实现
Eq
的前提是已经实现了PartialEq
,因为实现Eq
不需要额外的代码,只需要在实现了PartialEq
的基础上告诉编译器它的比较满足自反性就可以了. - 详见这个链接: https://bbs.huaweicloud.com/blogs/250275
- 如果我们想比较某个类型的两个值 x 和 y 是否相等(不等),例如:x == y (x != y),那么我们就必须为类型实现
- 使用浮点型时需要注意:
- 避免在浮点型上进行是否相等的比较
- 在使用时需要注意是否会出现 NaN 和 INFINITY, 如下是一些典型的情况:
- 对于非0除以0,得到的将是无穷大inf:
std::f64::INFINITY
- 而对于0除以0,将得到NaN:
std::f64::NAN
- 负数开方, 比如
(-42.0_f32).sqrt()
结果是 NAN
- 对于非0除以0,得到的将是无穷大inf:
- 可以使用
is_nan()
和is_finite()
判断结果进行处理 - 浮点数比较时, 可以利用差值落入区间的方式比较:
let a = 0.1 + 0.1;
let b = 0.2;
let diff = (b - a).abs();
// 预定义的一个容许偏差, 这样判断可以认为二者相等. f32 和 f64 均有 EPSILON 定义.
assert!(diff <= f32::EPSILON);
流程控制
For 循环
for in:
// 会 move container(所有权转移), 等效于 into_iter(container)
for item in container {
// ...
}
// 不会 move container, 等效于 container.iter(), item 为只读
for item in &container {
// ...
}
// 不会 move container, 等效于 container.iter_mut(), item 为读写
for item in &mut container {
// ...
}
如果不在循环中使用本地变量, 可以用下划线 _
代替:
for _ in 0..=10 { // 或 0..10(不包含上界)
// ...
}
While 循环
while my_vec.len() < 10 {
my_vec.push(item);
}
// 时间的实例
let limit = Duration::new(1, 0); // 1 秒区间
let start = Instant::now();
let mut count = 0;
while (Instant::now() - start) < limit {// 等待时间结束(忙等)
count += 1;
}
println!("{}", count);
无限循环
经常用来实现需要长时间运行的服务器:
loop {
// ...
}
loop {
let req = accept_request();
let result = some_processing(req);
send_response(result);
}
循环标签
常用语标记内外层循环, 语法是单引号 + 标签名, 比如 'outer
, 便于决定哪个循环需要 break/continue 等:
'outer: for x in 0.. {// 这里也是一种无限循环的方式
for y in 0.. {
for z in 0.. {
if x + y + z > 1000 {
break 'outer;
}
}
}
}
条件语句
if 语句用法类似, 略.
match
用来进行模式匹配.
函数
引用的生命期标记, 生命期只是一种开发时候的标记, 便于 borrow checker 检查传入的引用是否满足需要的生命期:
fn add_lifetime<'a, 'b>(i: &'a i32, j:&'b i32) -> i32 {
*i + *j
}
泛型函数的约束:
// 如下定义了一个泛型函数, 约束参数类型为支持"加操作"的类型
fn add<T: std::ops::Add<Output = T>>(i: T, j: T) -> T {
i + j
}
引用
引用是变量的一个指针, 通过 &
操作符进行, 解引用则使用 *
进行.
集合
数组
数组在编译时已知大小.
let a1 = [1, 2, 3];
let a2: [u8; 3] = [1, 2, 3]; // 指定初值
let a3: [u8; 3] = [0; 3]; // 重复初值
可以定义多维数组.
Rust 数组是连续的存储区域, 这样定义的数组会在栈上存放.
切片
切片是对集合中某个连续区域的引用. 比如 &str
是对字符串的切片.
Vector
Vector 是可增长的 list.
组合类型
- typealias 的写法:
type FilePath = String
- 在整个文件中应用某个注解的方法:
#![allow(dead_code)]
- 组合类型主要包括: enum 和 struct, 二者都可以包含方法的
impl
, 方法仍然有类方法和对象方法, 区别就是是否包含第一个参数是self
或&self
. - 使用
Result
来构造带 error 值, 使用Option
构造可空值. - 使用 trait 来定义接口.
- rust 的权限管理比较简单, 仅
pub
和不是 pub 的, 默认情况下, 所有的元素都是私有的.