Rust与Vector
Rust标准库中内置了许多集合,这与tuple有区别,集合是被存放在heap堆内存上,并且不需要声明时就指定长度,这也使其更加灵活。
我们常用的集合为:Vector,String,HashMap,本篇文章将介绍Vector这一数据类型
Vector
使用Vector存储多个值
Vector类型为Vec<T>
,其中关于Vector我们需要知道的是:
- 它由标准库提供
- 可以存储多个值
- 只能存储相同类型的数据
- 值在内存中是连续存放的
创建Vector
我们可以使用Vec::new()
来创建一个Vector:
fn main() {
let v: Vec<i32> = Vec::new();
}
一般我们不需要显示的指明vector的类型,当我们存入一个数据时,编译器会将这个值的类型作为vector的类型。
通常我们使用vec!
宏来通过初始值来创建一个Vec<T>
:
let v = vec![1, 2, 3];//v: Vec<i32>
更新Vector
我们使用push
向vector添加元素
我们先声明一个vector,但不声明类型,这时候会报错:
let mut v = Vec::new();//v:Vec<{unknown}, Global>
我们在后面使用push来添加元素,这时报错就消失了,并且我们会得到vector的类型:
let mut v = Vec::new();//v:Vec<i32, Global>
v.push(1);
v.push(2);
v.push(3);
v.push(4);
我们使用mut声明是因为我们会修改vector,向里面添加元素。
注意vector的类型是一致的:
let mut v = Vec::new();
v.push(1);
v.push(false);//error:mismatched types
删除Vector
与struct一样:
- 当vector离开作用域的时候,它会被清理掉
- 它所有的元素也会被清理掉
但是当vector中的元素被引用的时候,这里的情况就变复杂了,下面将对这种情况进行研究
读取vector的值
有两种方式可以读取vector的值:
- 使用索引
- 使用get方法
fn main() {
let v = vec![1, 2, 3, 4];
let third = &v[2];
//the third value of v is 3
println!("the third value of v is {}", third);
match v.get(2) {
// the third value of v is 3
Some(third) => println!("the third value of v is {}", third),
None => println!("there is no third element"),
}
}
使用索引和get处理访问越界的区别
- 索引:panic
- get:返回None
我们尝试将索引的值改为100,很明显,这个值超出了vector的范围:
let v = vec![1, 2, 3, 4];
let third = &v[100];//会引起panic
println!("the third value of v is {}", third);
而使用get方法不会:
fn main() {
let v = vec![1, 2, 3, 4];
match v.get(100) {
Some(third) => println!("the third value of v is {}", third),
None => println!("there is no third element"),
}
//there is no third element
}
这是因为,匹配的值的类型为一个Option<T>
,超出索引时,这个表达式的值为None
所有权和借用规则
不能在同一作用域内同时拥有可变和不可变引用:
let mut v = vec![1, 2, 3, 4];
let third = &v[2];
v.push(5); //cannot borrow `v` as mutable because it is also borrowed as immutable
println!("The Third v is {}", third);
报错的原因:vector在内存中的摆放是连续的,如果我们push,就可能没有这么大的内存块了。内存可能就会进行重新分配,然后就会从新找一块内存并且将值push到vector中,而原来的内存就可能被释放或者重新分配,这时候,我们的third
就变成一个悬空指针了,所以会报错。
遍历Vector中的值
使用for循环遍历:
let v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
}
//输出
//1
//2
//3
我们也可以修改vector中的值:
let mut v = vec![1, 2, 3];
for i in &mut v {
*i += 100;
}
for i in v {
println!("{}", i);
}
// 101
// 102
// 103
Vector+Enum的例子
我们知道vector中只能存放同种数据,那遇到存放不同类型的需求该怎么办呢?
我们在前面学到,enum的变体能够存储不同类型,并且能够附加数据。最重要的是,变体都在同一个enum下,也就是说它们的类型是一致的。
enum SpreadSheetCell {
Int(i32),
Float(f64),
Text(String),
}
let v = vec![
SpreadSheetCell::Int(22),
SpreadSheetCell::Float(2.2),
SpreadSheetCell::Text(String::from("nice demo")),
]; //v: Vec<SpreadSheetCell>
为什么rust需要在编译时就知道vector的值呢?因为vector是存放在heap上,这样可以提前知道需要多少内存。如果类型不同,就有可能遇到某些元素有某个方法,而某些没有。而通过Vector+Enum的组合,rust能够在编译时就知道所有情况。运行时就可以处理了。