|
| 1 | +# better_comprehension |
| 2 | + |
| 3 | +在rust中的集合推导式和迭代器推导式。提供更好的Rust使用体验 |
| 4 | + |
| 5 | +# 用法 |
| 6 | +语法源自[python推导式](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions) |
| 7 | + |
| 8 | +本库为Rust标准库中的所有集合类型提供宏,以及基于引用的迭代器 |
| 9 | + |
| 10 | +--- |
| 11 | +简单示例 |
| 12 | + |
| 13 | +```rust |
| 14 | +let vec_1 = vec!["AB".to_string(), "CD".to_string()]; |
| 15 | + |
| 16 | +let vec: Vec<String> = vector![x.clone() for x in vec_1]; |
| 17 | +assert_eq!(vec, vec!["AB".to_string(), "CD".to_string()]); |
| 18 | +``` |
| 19 | + |
| 20 | +--- |
| 21 | +你也可以在推导式中使用模式 |
| 22 | +```rust |
| 23 | +struct Person { |
| 24 | + name: String, |
| 25 | + age: i32, |
| 26 | +} |
| 27 | +let people = [Person { name: "Joe".to_string(), age: 20 }, |
| 28 | + Person { name: "Bob".to_string(), age: 25 }]; |
| 29 | + |
| 30 | +let vec_deque = vec_deque![name.clone() for Person { name, .. } in people]; |
| 31 | +assert_eq!(vec_deque, VecDeque::from(["Joe".to_string(), "Bob".to_string()])); |
| 32 | +``` |
| 33 | +--- |
| 34 | + |
| 35 | +过滤集合中的值 |
| 36 | +```rust |
| 37 | +let linked_list = linked_list![ i*2 for i in 1..=3 if i != 2 ]; |
| 38 | +assert_eq!(linked_list, LinkedList::from([2, 6])); |
| 39 | +``` |
| 40 | +--- |
| 41 | + |
| 42 | +根据条件返回不同的值 |
| 43 | +```rust |
| 44 | +let b_tree_set = b_tree_set!{ |
| 45 | + i if i-1 == 0 else i+10 |
| 46 | + for i in 1..=3 if i != 2 |
| 47 | + }; |
| 48 | +assert_eq!(b_tree_set, BTreeSet::from([1, 13])); |
| 49 | +``` |
| 50 | + |
| 51 | +--- |
| 52 | +嵌套推导式 |
| 53 | +```rust |
| 54 | +let binary_heap = binary_heap![ |
| 55 | + i if (i-1 == 0 || j -2 == 0) else i+10 |
| 56 | + for i in 1..=3 if i != 2 |
| 57 | + for j in 1..=3 if j+i != 4]; |
| 58 | +assert_eq!(binary_heap.into_sorted_vec(), vec![1, 1, 3, 13]); |
| 59 | +``` |
| 60 | +--- |
| 61 | + |
| 62 | +和python的推导式一样, 本库的for循环是从上到下读取的. |
| 63 | +```rust |
| 64 | +let vec = vector![ |
| 65 | + (top,bottom) |
| 66 | + for top in 1..=3 if top != 2 |
| 67 | + for bottom in 4..=6 if bottom+top != 4]; |
| 68 | +assert_eq!(vec, vec![(1, 4), (1, 5), (1, 6), (3, 4), (3, 5), (3, 6)]); |
| 69 | +``` |
| 70 | + |
| 71 | +需要注意的是, 由于在rust中, for loop 是消耗所有权的. |
| 72 | + |
| 73 | +所以通常来说, 对于多层循环, 如果你希望原容器被消耗, 你应该写成如下这样: |
| 74 | +```rust |
| 75 | +let vec_1 = vec!["ABC".to_string(), "DEF".to_string()]; |
| 76 | +let vec_2 = vec!["abc".to_string(), "def".to_string()]; |
| 77 | +let vec_3 = vec![123, 456]; |
| 78 | +let vec = { |
| 79 | + // 遮蔽想消耗的变量 |
| 80 | + let vec_1 = vec_1; |
| 81 | + let vec_3 = vec_3; |
| 82 | + |
| 83 | + let mut vec = vec![]; |
| 84 | + // 在外层循环里, 你可以选择使用iter()保留所有权 |
| 85 | + for i in vec_1.iter() { |
| 86 | + if i == "ABC" { |
| 87 | + // 在内层循环里, 你必须使用iter() , 否则所有权会在第一次被转移 |
| 88 | + for j in vec_2.iter() { |
| 89 | + if j == "abc" { |
| 90 | + // 如果不使用iter(), 那么vec_3的所有权会在第一次被转移 |
| 91 | + for k in vec_3.iter() { |
| 92 | + if k == &123 { |
| 93 | + // 仅在必要时使用clone, 以避免不必要的资源浪费 |
| 94 | + vec.push((i.clone(), j.clone(), *k)); |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + vec |
| 102 | +}; |
| 103 | +// println!("{:?}", vec_1); // borrow of moved value |
| 104 | +println!("{:?}", vec_2); // work well |
| 105 | +// println!("{:?}", vec_3); // borrow of moved value |
| 106 | +``` |
| 107 | + |
| 108 | +但在本库中, 你不需要这么做, 提供的宏会自动帮你处理这些问题. |
| 109 | + |
| 110 | +你唯一需要做的就是在你想要保留所有权的变量后面加上.iter() 或 使用 & , 其余会在宏内自动处理. |
| 111 | +```rust |
| 112 | +let vec_1 = vec!["ABC".to_string(), "DEF".to_string()]; |
| 113 | +let vec_2 = vec!["abc".to_string(), "def".to_string()]; |
| 114 | +let vec_3 = vec![123, 456]; |
| 115 | + |
| 116 | +let vec = vector![ |
| 117 | + (i.clone(),j.clone(),*k) |
| 118 | + for i in vec_1 if i == "ABC" |
| 119 | + for j in vec_2.iter() if j == "abc" |
| 120 | + // for j in &vec_2 if j == "abc" 这种写法也是可以的 |
| 121 | + for k in vec_3 if k == &123 |
| 122 | +]; |
| 123 | +// println!("{:?}", vec_1); // borrow of moved value |
| 124 | +println!("{:?}", vec_2); // work well |
| 125 | +// println!("{:?}", vec_3); // borrow of moved value |
| 126 | +``` |
| 127 | + |
| 128 | +同时, 该库还支持键值对容器类型, HashMap, BTreeMap |
| 129 | + |
| 130 | +```rust |
| 131 | +let vec_key = vec!["key_1".to_string(), "key_2".to_string(), "key_3".to_string()]; |
| 132 | + let vec_value = [1, 2, 3]; |
| 133 | + let hash_map = hash_map!{ |
| 134 | + key.clone() : *value // 三种键值对分隔符都支持 |
| 135 | + // key.clone() => *value |
| 136 | + // key.clone() , *value |
| 137 | + for key in vec_key |
| 138 | + for value in vec_value |
| 139 | + }; |
| 140 | + assert_eq!( |
| 141 | + hash_map, |
| 142 | + HashMap::from([ |
| 143 | + ("key_1".to_string(), 3), |
| 144 | + ("key_2".to_string(), 3), |
| 145 | + ("key_3".to_string(), 3) |
| 146 | + ]) |
| 147 | + ); |
| 148 | +``` |
| 149 | +--- |
| 150 | + |
| 151 | +该库也支持迭代器推导式, 但不同于上面的集合推导式 |
| 152 | + |
| 153 | +该迭代器推导式是基于引用的, 所以不会消耗所有权 |
| 154 | + |
| 155 | +除此之外的写法与集合推导式完全相同 |
| 156 | +```rust |
| 157 | +let vec_1 = ["123".to_string(), "456".to_string(), "789".to_string()]; |
| 158 | +let vec_2 = ["ABC".to_string(), "DEF".to_string(), "GHI".to_string()]; |
| 159 | + |
| 160 | +let mut result3 = iterator_ref![ |
| 161 | +(x.clone(), y.clone()) if x.contains("1") else (y.clone(), x.clone()) |
| 162 | +for x in vec_1 if x.contains("1") || x.contains("7") |
| 163 | +for i in 1..=2 |
| 164 | +for y in vec_2 if y.contains("D") || x.contains("3")]; |
| 165 | + |
| 166 | + |
| 167 | +for _ in 0..=9 { |
| 168 | + println!("{:?}", result3.next()); |
| 169 | +} |
| 170 | +/* |
| 171 | +Some(("123", "ABC")) |
| 172 | +Some(("123", "DEF")) |
| 173 | +Some(("123", "GHI")) |
| 174 | +Some(("123", "ABC")) |
| 175 | +Some(("123", "DEF")) |
| 176 | +Some(("123", "GHI")) |
| 177 | +Some(("789", "DEF")) |
| 178 | +Some(("789", "DEF")) |
| 179 | +None |
| 180 | +None |
| 181 | +*/ |
| 182 | +``` |
| 183 | + |
| 184 | +以上写法与下面的写法是完全的等价形式 |
| 185 | +```rust |
| 186 | +let vec_1 = ["123".to_string(), "456".to_string(), "789".to_string()]; |
| 187 | +let vec_2 = ["ABC".to_string(), "DEF".to_string(), "GHI".to_string()]; |
| 188 | + |
| 189 | +let mut result3 = { |
| 190 | + let vec_2 = vec_2.iter().collect::<Vec<_>>(); |
| 191 | + let vec_1 = vec_1.iter().collect::<Vec<_>>(); |
| 192 | + (vec_1).into_iter().filter_map(move |x| { |
| 193 | + (x.contains("1") || x.contains("7")).then(|| { |
| 194 | + let vec_2 = vec_2.clone(); |
| 195 | + (1..=2).into_iter().filter_map(move |i| { |
| 196 | + (true).then(|| { |
| 197 | + let vec_2 = vec_2.clone(); |
| 198 | + (vec_2).into_iter().filter_map(move |y| { |
| 199 | + (y.contains("D") || x.contains("3")).then(|| { |
| 200 | + if x.contains("1") { |
| 201 | + (x.clone(), y.clone()) |
| 202 | + } else { |
| 203 | + (y.clone(), x.clone()) |
| 204 | + } |
| 205 | + }) |
| 206 | + }) |
| 207 | + }) |
| 208 | + }) |
| 209 | + }) |
| 210 | + .flatten() |
| 211 | + .flatten() |
| 212 | +}; |
| 213 | +``` |
| 214 | + |
| 215 | + |
| 216 | +# 一些细节 |
| 217 | + |
| 218 | +vector! : 使用push()添加元素 |
| 219 | + |
| 220 | +vec_deque! : 使用push_back()添加元素 |
| 221 | + |
| 222 | +linked_list! : 使用push_back()添加元素 |
| 223 | + |
| 224 | +hash_set! : 使用insert()添加元素 |
| 225 | + |
| 226 | +hash_map! : 使用insert()添加键值对 |
| 227 | + |
| 228 | +b_tree_map! : 使用insert()添加键值对 |
| 229 | + |
| 230 | +b_tree_set! : 使用insert()添加元素 |
| 231 | + |
| 232 | +binary_heap! : 使用push()添加元素 |
0 commit comments