Vector

相比 [T; N] 形式的数组, Vector 最大的特点就是可以动态调整长度。

基本操作

  1. 🌟🌟🌟
2. fn main() {
3. let arr: [u8; 3] = [1, 2, 3];

5. let v = Vec::from(arr);
6. is_vec(v);

8. let v = vec![1, 2, 3];
9. is_vec(v);

11. // vec!(..) 和 vec![..] 是同样的宏,宏可以使用 []、()、{}三种形式,因此...
12. let v = vec!(1, 2, 3);
13. is_vec(v);

15. // ...在下面的代码中, v 是 Vec<[u8; 3]> , 而不是 Vec<u8>
16. // 使用 Vec::new 和 `for` 来重写下面这段代码
17. let v1 = vec!(arr);
18. is_vec(v1);

20. assert_eq!(v, v1);

22. println!("Success!")
23. }

25. fn is_vec(v: Vec<u8>) {}
  1. 🌟🌟 Vec 可以使用 extend 方法进行扩展
2. // 填空
3. fn main() {
4. let mut v1 = Vec::from([1, 2, 4]);
5. v1.pop();
6. v1.push(3);

8. let mut v2 = Vec::new();
9. v2.__;

11. assert_eq!(v1, v2);

13. println!("Success!")
14. }

将 X 类型转换(From/Into 特征)成 Vec

只要为 Vec 实现了 From<T> 特征,那么 T 就可以被转换成 Vec。

  1. 🌟🌟🌟
2. // 填空
3. fn main() {
4. // array -> Vec
5. // impl From<[T; N]> for Vec
6. let arr = [1, 2, 3];
7. let v1 = __(arr);
8. let v2: Vec<i32> = arr.__();

10. assert_eq!(v1, v2);

12. // String -> Vec
13. // impl From<String> for Vec
14. let s = "hello".to_string();
15. let v1: Vec<u8> = s.__();

17. let s = "hello".to_string();
18. let v2 = s.into_bytes();
19. assert_eq!(v1, v2);

21. // impl<'_> From<&'_ str> for Vec
22. let s = "hello";
23. let v3 = Vec::__(s);
24. assert_eq!(v2, v3);

26. // 迭代器 Iterators 可以通过 collect 变成 Vec
27. let v4: Vec<i32> = [0; 10].into_iter().collect();
28. assert_eq!(v4, vec![0; 10]);

30. println!("Success!")
31. }

索引

  1. 🌟🌟🌟
2. // 修复错误并实现缺失的代码
3. fn main() {
4. let mut v = Vec::from([1, 2, 3]);
5. for i in 0..5 {
6. println!("{:?}", v[i])
7. }

9. for i in 0..5 {
10. // 实现这里的代码...
11. }

13. assert_eq!(v, vec![2, 3, 4, 5, 6]);

15. println!("Success!")
16. }

切片

与 String 的切片类似, Vec 也可以使用切片。如果说 Vec 是可变的,那它的切片就是不可变或者说只读的,我们可以通过 & 来获取切片。

在 Rust 中,将切片作为参数进行传递是更常见的使用方式,例如当一个函数只需要可读性时,那传递 Vec 或 String 的切片 &[T] / &str 会更加适合。

  1. 🌟🌟
2. // 修复错误
3. fn main() {
4. let mut v = vec![1, 2, 3];

6. let slice1 = &v[..];
7. // 越界访问将导致 panic.
8. // 修改时必须使用 `v.len`
9. let slice2 = &v[0..4];

11. assert_eq!(slice1, slice2);

13. // 切片是只读的
14. // 注意:切片和 `&Vec` 是不同的类型,后者仅仅是 `Vec` 的引用,并可以通过解引用直接获取 `Vec`
15. let vec_ref: &mut Vec<i32> = &mut v;
16. (*vec_ref).push(4);
17. let slice3 = &mut v[0..3];
18. slice3.push(4);

20. assert_eq!(slice3, &[1, 2, 3, 4]);

22. println!("Success!")
23. }

容量

容量 capacity 是已经分配好的内存空间,用于存储未来添加到 Vec 中的元素。而长度 len 则是当前 Vec 中已经存储的元素数量。如果要添加新元素时,长度将要超过已有的容量,那容量会自动进行增长:Rust 会重新分配一块更大的内存空间,然后将之前的 Vec 拷贝过去,因此,这里就会发生新的内存分配( 目前 Rust 的容量调整策略是加倍,例如 2 -> 4 -> 8 ..)。

若这段代码会频繁发生,那频繁的内存分配会大幅影响我们系统的性能,最好的办法就是提前分配好足够的容量,尽量减少内存分配。

  1. 🌟🌟
1. // 修复错误
2. fn main() {
3. let mut vec = Vec::with_capacity(10);

5. assert_eq!(vec.len(), __);
6. assert_eq!(vec.capacity(), 10);

8. // 由于提前设置了足够的容量,这里的循环不会造成任何内存分配...
9. for i in 0..10 {
10. vec.push(i);
11. }
12. assert_eq!(vec.len(), __);
13. assert_eq!(vec.capacity(), __);

15. // ...但是下面的代码会造成新的内存分配
16. vec.push(11);
17. assert_eq!(vec.len(), 11);
18. assert!(vec.capacity() >= 11);

20. // 填写一个合适的值,在 `for` 循环运行的过程中,不会造成任何内存分配
21. let mut vec = Vec::with_capacity(__);
22. for i in 0..100 {
23. vec.push(i);
24. }

26. assert_eq!(vec.len(), __);
27. assert_eq!(vec.capacity(), __);

29. println!("Success!")
30. }

在 Vec 中存储不同类型的元素

Vec 中的元素必须是相同的类型,例如以下代码会发生错误:

1. fn main() {
2. let v = vec![1, 2.0, 3];
3. }

但是我们可以使用枚举或特征对象来存储不同的类型.

  1. 🌟🌟
1. #[derive(Debug)]
2. enum IpAddr {
3. V4(String),
4. V6(String),
5. }
6. fn main() {
7. // 填空
8. let v : Vec<IpAddr>= __;

10. // 枚举的比较需要派生 PartialEq 特征
11. assert_eq!(v[0], IpAddr::V4("127.0.0.1".to_string()));
12. assert_eq!(v[1], IpAddr::V6("::1".to_string()));

14. println!("Success!")
15. }
  1. 🌟🌟
1. trait IpAddr {
2. fn display(&self);
3. }

5. struct V4(String);
6. impl IpAddr for V4 {
7. fn display(&self) {
8. println!("ipv4: {:?}",self.0)
9. }
10. }
11. struct V6(String);
12. impl IpAddr for V6 {
13. fn display(&self) {
14. println!("ipv6: {:?}",self.0)
15. }
16. }

18. fn main() {
19. // 填空
20. let v: __= vec![
21. Box::new(V4("127.0.0.1".to_string())),
22. Box::new(V6("::1".to_string())),
23. ];

25. for ip in v {
26. ip.display();
27. }
28. }

你可以在这里找到答案(在 solutions 路径下)