Options类型和错误处理
enum Option {
None,
Some(T),
}
Option 系统类型,可以传入任何值 ,包含 2个函数 Some() Noe() 通过匹配 match 可以获取到 内部的值,这样可以避免 直接 访问 变量本身, 如 在 如c这样语言里 如果直接 使用了nil的指针 会报错,在Rust里面 我们 不直接使访问,而是通过间接的 通过系统函数match 来匹配 如果为 空 匹配的就是None 的处理方法。
代码示例:
let a:Option<f32> = Some(100.111);
match a {
Some(i) => {
println!("{}",i);
},
None =>{
println!("has no value");
}
}
let a1:Option<f32> = Option::None;
match a1 {
Some(i) => {
println!("{}",i);
},
None =>{
println!("has no value");
}
}
unwrap
下面代码,就是Option 对 空的检查, 类比 Go语言里面的 if var == nil{panic(”error“)} 。
impl<T> Option<T> {
fn unwrap(self) -> T {
match self {
Option::Some(val) => val,
Option::None =>
panic!("called `Option::unwrap()` on a `None` value"),
}
}
}
unwrap_or
对于None的处理情况,我们可以提供一个默认值作为返回。
fn unwrap_or<T>(option: Option<T>, default: T) -> T {
match option {
None => default,
Some(value) => value,
}
}
print!("{}",unwrap_or(a1, 1 as f32)); //如果为None 默认返回1
and_then
fn and_then<F, T, A>(option: Option<T>, f: F) -> Option<A>
where F: FnOnce(T) -> Option<A> {
match option {
None => None,
Some(value) => f(value),
}
}
与map类似,但返回的是另一个Option。
Result
enum Result<T, E> {
Ok(T),
Err(E),
}
与Options类似,它包含了,返回结果 或者 错误产生的原因。
unwrap
impl<T, E: ::std::fmt::Debug> Result<T, E> {
fn unwrap(self) -> T {
match self {
Result::Ok(val) => val,
Result::Err(err) =>
panic!("called `Result::unwrap()` on an `Err` value: {:?}", err),
}
}
}
和Options 类似大同小异,None 变成了 Error的原因。
查找
文本搜素类
//寻找文本的索引
fn extension(file_name: &str) -> Option<&str> {
find(file_name, '.').map(|i| &file_name[i+1..])
}
Rust 迭代
let mut v = vec![1, 2, 3, 4, 5, 6, 7];
let mut m = **v.get(1).unwrap().borrow_mut();
for x in v.iter_mut(){
*x += 2;
}
取数组第N个元素
let mut v = vec![1, 2, 3, 4, 5, 6, 7];
let mut m = v.get_mut(2).unwrap();
*m = 100;
Rust Vec
Vec
包含(指针、容量、长度)
pub struct Vec<T> {
ptr: *mut T,
cap: usize,
len: usize,
}
Vec::with_capacity(0)
随机访问
不安全访问(直接通过下标):
vec[index]
安全访问:
vec.get(i)
引用和可变引用
一个数据同时可以有多个引用,同时只能存在一个可变借用,而且一旦 存在可变借用那么之前所有的可变引用将会变得无法使用(编译器报错),如果有一个可变借用那么将无法再.
let mut a = String::from("xiaoming");
let b = & mut a; //可变引用
let c = a; //在 b 借用了 a 之后 再引用 a
b.push("a".parse().unwrap()); //改变 b的值
println!("{}",a);
println!("{}",b);
println!("{}",c);
上述代码就是违反了,定义所以无法通过!
定义数据结构
#[derive(Debug)]
struct User{
name:String,
count:String,
nonce:u64,
active:bool,
}
let mut m = User{ name: String::from("xiaoming"),count:String::from("99"),nonce:34,active:false};
m.name = String::from("caomao");//修改可变结构体
println!("{:?}",m);//打印输出
切片
let s =String::from("hello world!");
let h = &s[0..5]; //前五个字节 左闭右开
let h = &s[0..=4];//0 到 4个字节
let h = &s[..=4];//五四个字节
let h = &s[..];//取全部
println!("h= {}",h);
Box堆上空间
Box 是通过创建一个指针的方式,将内容生成在堆上,而指针指向对的空间。 对比Vec 通过 Box 内存消耗更多,但是通过指针的好处是 不管你是一个i32 string还是对象 都可以通过一个固定大小的指针来声明,在许多面向对象的 语言里面,Java/Python/Ruby/JavaScript 等都是通过Box指针这种方式实现的。
Vec<i32>
(stack) (heap)
┌──────┐ ┌───┐
│ vec1 │──→│ 1 │
└──────┘ ├───┤
│ 2 │
├───┤
│ 3 │
├───┤
│ 4 │
└───┘
Vec<Box<i32>>
(stack) (heap) ┌───┐
┌──────┐ ┌───┐ ┌─→│ 1 │
│ vec2 │──→│ │─┘ └───┘
└──────┘ ├───┤ ┌───┐
│ │───→│ 2 │
├───┤ └───┘
│ │─┐ ┌───┐
├───┤ └─→│ 3 │
│ │─┐ └───┘
└───┘ │ ┌───┐
└─→│ 4 │
└───┘
在python里面的list 可以存放任何类型对象,实现上与Vec<Box>也是类似的。
有的时候编译器不能在编译期间确定数据大小 如Vec String,也就无法计算出在栈上需要分配多少空间,而通过指针 即使不确定数据类型的大小,但是可以在运行时分配在栈上,指针作为引用,这样大小就是可知的可以分配在栈上。