Skip to main content

Rust 基础整理

数值类型

  1. 使用 0b/0o/0x 来表示 2/8/16 进制数
  2. 数值类型有如下: i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, iszie, usize, 其中 iszie 和 usize 分别根据 CPU 的字长不同可以是 32 bit 或 64 bit.
  3. 不同类型转换使用 try_into, 也可以使用 as
  4. PartialEqEq 的区别:
    • 如果我们想比较某个类型的两个值 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
  5. 使用浮点型时需要注意:
    • 避免在浮点型上进行是否相等的比较
    • 在使用时需要注意是否会出现 NaN 和 INFINITY, 如下是一些典型的情况:
      • 对于非0除以0,得到的将是无穷大inf: std::f64::INFINITY
      • 而对于0除以0,将得到NaN: std::f64::NAN
      • 负数开方, 比如 (-42.0_f32).sqrt() 结果是 NAN
    • 可以使用 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.

组合类型

  1. typealias 的写法: type FilePath = String
  2. 在整个文件中应用某个注解的方法: #![allow(dead_code)]
  3. 组合类型主要包括: enum 和 struct, 二者都可以包含方法的 impl, 方法仍然有类方法和对象方法, 区别就是是否包含第一个参数是 self&self.
  4. 使用 Result 来构造带 error 值, 使用 Option 构造可空值.
  5. 使用 trait 来定义接口.
  6. rust 的权限管理比较简单, 仅 pub 和不是 pub 的, 默认情况下, 所有的元素都是私有的.