开发rust程序过程中遇到的问题以及解决方法

错误处理

  • 对于 ResultOption等类型,如果使用 unwrapexpect等方法,会直接导致panic

  • 对于 Result 类型,如果遇到错误只需要返回 None,那么可以使用如下简单的语法来替代 match :

    1
    let some_var = something_that_returns_result().ok()?;

    其中,Result::ok() 函数将 Result 转换为 Option

    • 对于 Ok(val),返回 Some(val)
    • 对于 Err(some_error),返回 None

    ? 提取 Option 中的内容,如果为 None,则返回 None

slice复制

使用copy_from_slice将一个slice的内容复制到另外一个slice时,要求两个slice的长度相同,因此对于要将[u8]转为[u8; usize]的场景,需要使用以下代码:

1
2
3
4
let v: Vec<u8> = vec![1,2,3];
let vs: &[u8] = v.as_slice();
let mut vs2: [u8; 32] = [0; 32];
vs2[..3].copy_from_slice(vs);

关于所有权

  • 定长的变量存放在栈中,默认实现 Copy 特征,拷贝时直接在栈上复制一个副本,为浅拷贝

  • 不定长或可变的变量存放在堆中,并将其对应的指针压入栈中,拷贝时会转移所有权,若需要原变量也保持所有权,需要进行深拷贝,即将堆中存放的数据也拷贝一份

循环

使用方法 等价使用方式 所有权
for item in collection for item in IntoIterator::into_iter(collection) 转移所有权
for item in &collection for item in collection.iter() 不可变借用
for item in &mut collection for item in collection.iter_mut() 可变借用

Trait

  • 孤儿规则:如果你想要为类型 A 实现特征 T,那么 A 或者 T 至少有一个是在当前作用域中定义的

    • eg:无法在当前作用域中,为 String 类型实现 Display 特征,因为它们俩都定义在标准库中,其定义所在的位置都不在当前作用域
  • 调用方法需要引入特征:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    use std::convert::TryInto;

    fn main() {
    let a: i32 = 10;
    let b: u16 = 100;

    let b_ = b.try_into()
    .unwrap();

    if a < b_ {
    println!("Ten is less than one hundred.");
    }
    }
  • 特征对象: Box<dyn Trait>&dyn Trait

Box::leak

需要一个在运行期初始化的值,但是可以全局有效,也就是和整个程序活得一样久

  • eg. 可以把一个 String 类型,变成一个 'static 生命周期的 &str 类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    fn main() {
    let s = gen_static_str();
    println!("{}", s);
    }

    fn gen_static_str() -> &'static str{
    let mut s = String::new();
    s.push_str("hello, world");

    Box::leak(s.into_boxed_str())
    }

Stack overflow

例如定义一个跳表节点

1
2
3
4
5
6
struct Node {
skips: Vec<Option<*mut Node>>,
next: Option<Box<Node>>,
key: Vec<u8>,
value: Vec<u8>,
}

若跳表中节点很多,则在drop头节点时,默认会采用递归的方式来清除,这样会导致爆栈,因此需要自定义迭代方式的drop

1
2
3
4
5
6
7
8
9
impl Drop for Node {
fn drop(&mut self) {
if let Some(mut next) = self.next.take() {
while let Some(n) = next.next.take() {
next = n;
}
}
}
}