Rust 动态数组
动态数组:Vec< T >,T表示泛型。
创建动态数组
fn main() { let v: Vec<i32> = Vec::new(); }
创建动态数组的声明需要声明类型,因为数组中没有数据,rust无法推导。如果你放入了数据,rust一般能推导出正确的数据类型。
rust提供了vec!宏,可以根据我们的值来创建一个新的动态数组。
fn main() { let v = vec![1, 2, 3]; }
在动态数组中加入数据
使用push在数组的最后加入数据,注意修改数组要加mut,因为你push了i32的数据,所以rust推导出了vec的类型。
fn main() { let mut v = Vec::new(); v.push(5); v.push(6); v.push(7); v.push(8); }
销毁动态数组也会销毁其中的元素
和struct一样,如果动态数组离开作用域,那么动态数组也会被销毁
fn main() { { let v = vec![1, 2, 3, 4]; // do stuff with v } // <- v goes out of scope and is freed here }
但如果有引用指向了动态数组中的数据,情况会变得复杂。
读取动态数组中的元素
有两种方法:
fn main() { let v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; println!("The third element is {}", third); match v.get(2) { Some(third) => println!("The third element is {}", third), None => println!("There is no third element."), } }
可以看到第一种是使用了索引,第二种使用了get方法。 第一种方法是一个引用,第二种方法返回的是一个option。 当数组越界时,这两种方法的不同之处就体现出来了。 当使用引用越界时,程序会直接崩溃,如果你希望程序崩溃,索引是可用的。 当使用get越界时,程序只是返回了一个none,程序能继续运行。 可以视情况使用。
在存在指向动态数组元素的引用时尝试向动态数组中添加元素
最恶心的不是这个,而是关于可变引用的所有权规则。 之前我们说过,在同一作用域中如果存在一个可变引用,就不能使用其他任何引用。 接下来看这个错误代码:
//错误代码 fn main() { let mut v = vec![1, 2, 3, 4, 5]; let first = &v[0]; v.push(6); println!("The first element is: {}", first); }
这个例子首先声明了一个可变的动态数组,然后使用了一个不可变引用,最后向数组中push了一个数据。
我们先来了解一下vec的原理,其实和c++的stl中的vector原理时一样的,我就从以前博客复制下来这一段:
值得注意的一点,当插入时容量不够:
- 会先开辟新的内存空间,新空间大小为 old_size + max(old_size, n)。
- 然后再将旧数据和新数据放入新空间中。
- 释放旧空间。
意思就是说,vec的地址空间可能会因为push变动。
至于上面代码为什么错误,官方的解释时,因为vec的地址空间可能因为push变动,所以不可变引用将会时危险的。
但我的理解却和官方有点不一样,看到这篇博客的就当笑话看看:因为v.push是一个方法,所以有&self参数,因为会修改v的数据,所以应该是&mut self,是一个可变引用,如果之前使用了不可变引用就会违背关于可变引用的所有权规则。所以会报错。
遍历动态数组中的值
一种是直接用索引遍历,缺点是可能发生数组越界:
fn main(){ let v=vec![1,2,3,4,5,6]; for i in 0..5{ println!("{}",v[i]); } }
第二种是通过不可变引用:
fn main() { let v = vec![100, 32, 57]; for i in &v { println!("{}", i); } }
第三种是通过可变引用,还可以修改其值:
fn main() { let mut v = vec![100, 32, 57]; for i in &mut v { *i += 50; } }
使用枚举类型来存储多个类型的值
动态数组只能存储相同类型的值,有些情况下我们需要在数组中存不同类型的值,我们可以通过枚举类型来实现:使用动态数组存储枚举类型。
fn main() { enum SpreadsheetCell { Int(i32), Float(f64), Text(String), } let row = vec![ SpreadsheetCell::Int(3), SpreadsheetCell::Text(String::from("blue")), SpreadsheetCell::Float(10.12), ]; }
但是有些情况下,你无法枚举你所需要的所有类型,那么我们会在之后讨论动态trait。
下一章:Rust 所有权
rust通过所有权系统管理内存,该系统具有一组在编译时检查的规则。程序运行时,所有所有权功能都不会减慢其运行速度。 所有权规则 首先,让我们看一下所有权规则。在通过示例进行说明时,请牢记以下规则: Rust中的每个值都有一 ...