开发rust程序过程中遇到的问题以及解决方法
错误处理
-
对于
Result、Option等类型,如果使用unwrap、expect等方法,会直接导致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 | let v: Vec<u8> = vec![1,2,3]; |
关于所有权
-
定长的变量存放在栈中,默认实现
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特征,因为它们俩都定义在标准库中,其定义所在的位置都不在当前作用域
- eg:无法在当前作用域中,为
-
调用方法需要引入特征:
1
2
3
4
5
6
7
8
9
10
11
12
13use 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
11fn 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 | struct Node { |
若跳表中节点很多,则在drop头节点时,默认会采用递归的方式来清除,这样会导致爆栈,因此需要自定义迭代方式的drop
1 | impl Drop for Node { |