|
| 1 | +# better_comprehension |
| 2 | + |
| 3 | +在rust中的集合推导式和迭代器推导式。提供更好的Rust使用体验。 |
| 4 | +Collection comprehension and Iterator comprehension in Rust. And it provides a better experience in Rust. |
| 5 | + |
| 6 | +# Usage |
| 7 | +语法源自[python推导式](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions)。 |
| 8 | +本库为Rust标准库中的所有集合类型提供宏,以及基于引用的迭代器。 |
| 9 | +The syntax is derived from [Python's comprehension](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions). |
| 10 | +This library provides macros for all collection types in the Rust standard library and an Iterator based on references. |
| 11 | + |
| 12 | +简单示例 |
| 13 | +simple example |
| 14 | +```rust |
| 15 | +let vec_1 = vec!["AB".to_string(), "CD".to_string()]; |
| 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 | +You can also use patterns in it |
| 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 | +let vec_deque = vec_deque![name.clone() for Person { name, .. } in people]; |
| 30 | +assert_eq!(vec_deque, VecDeque::from(["Joe".to_string(), "Bob".to_string()])); |
| 31 | +``` |
| 32 | + |
| 33 | +过滤值 |
| 34 | +filtering values |
| 35 | +```rust |
| 36 | +let linked_list = linked_list![ i*2 for i in 1..=3 if i != 2 ]; |
| 37 | +assert_eq!(linked_list, LinkedList::from([2, 6])); |
| 38 | +``` |
| 39 | + |
| 40 | +根据条件返回不同的值 |
| 41 | +return different values based on conditions |
| 42 | +```rust |
| 43 | +let b_tree_set = b_tree_set!{ |
| 44 | + i if i-1 == 0 else i+10 |
| 45 | + for i in 1..=3 if i != 2 |
| 46 | + }; |
| 47 | +assert_eq!(b_tree_set, BTreeSet::from([1, 13])); |
| 48 | +``` |
| 49 | + |
| 50 | +嵌套推导式 |
| 51 | +nested comprehension |
| 52 | +```rust |
| 53 | +let binary_heap = binary_heap![ |
| 54 | + i if (i-1 == 0 || j -2 == 0) else i+10 |
| 55 | + for i in 1..=3 if i != 2 |
| 56 | + for j in 1..=3 if j+i != 4]; |
| 57 | +assert_eq!(binary_heap.into_sorted_vec(), vec![1, 1, 3, 13]); |
| 58 | +``` |
| 59 | + |
| 60 | +和python的推导式一样, 本库的for循环是从上到下读取的. |
| 61 | +the reading order of the for loop in this library is from top to bottom, just like Python's comprehension. |
| 62 | +```rust |
| 63 | +let vec = vector![ |
| 64 | + (top,bottom) |
| 65 | + for top in 1..=3 if top != 2 |
| 66 | + for bottom in 4..=6 if bottom+top != 4]; |
| 67 | +assert_eq!(vec, vec![(1, 4), (1, 5), (1, 6), (3, 4), (3, 5), (3, 6)]); |
| 68 | +``` |
| 69 | + |
| 70 | +需要注意的是, 由于在rust中, for loop 是消耗所有权的. |
| 71 | +所以通常来说, 对于多层循环, 如果你希望原容器被消耗, 你应该写成如下这样: |
| 72 | +Note that in Rust, for loops consume ownership. |
| 73 | +So typically, for nested loops, if you want the original container to be consumed, you should write it like this: |
| 74 | + |
| 75 | +```rust |
| 76 | +let vec_1 = vec!["ABC".to_string(), "DEF".to_string()]; |
| 77 | +let vec_2 = vec!["abc".to_string(), "def".to_string()]; |
| 78 | +let vec_3 = vec![123, 456]; |
| 79 | +let vec = { |
| 80 | + // 遮蔽想消耗的变量 |
| 81 | + // shadow the variable you want to consume |
| 82 | + let vec_1 = vec_1; |
| 83 | + let vec_3 = vec_3; |
| 84 | + |
| 85 | + let mut vec = vec![]; |
| 86 | + // 在外层循环里, 你可以选择使用iter()保留所有权 |
| 87 | + // In the outer loop, you can choose to use iter() to keep ownership |
| 88 | + for i in vec_1.iter() { |
| 89 | + if i == "ABC" { |
| 90 | + // 在内层循环里, 你必须使用iter() , 否则所有权会在第一次被转移 |
| 91 | + // In the inner loop, you must use iter(), |
| 92 | + // otherwise ownership will be transferred for the first time |
| 93 | + for j in vec_2.iter() { |
| 94 | + if j == "abc" { |
| 95 | + // 如果不使用iter(), 那么vec_3的所有权会在第一次被转移 |
| 96 | + // If you do not use iter(), |
| 97 | + // then the ownership of vec_3 will be transferred for the first time |
| 98 | + for k in vec_3.iter() { |
| 99 | + if k == &123 { |
| 100 | + // 仅在必要时使用clone, 以避免不必要的资源浪费 |
| 101 | + // Only use clone when necessary to avoid unnecessary resource waste |
| 102 | + vec.push((i.clone(), j.clone(), *k)); |
| 103 | + } |
| 104 | + } |
| 105 | + } |
| 106 | + } |
| 107 | + } |
| 108 | + } |
| 109 | + vec |
| 110 | +}; |
| 111 | +// println!("{:?}", vec_1); // borrow of moved value |
| 112 | +println!("{:?}", vec_2); // work well |
| 113 | +// println!("{:?}", vec_3); // borrow of moved value |
| 114 | +``` |
| 115 | + |
| 116 | +但在本库中, 你不需要这么做, 提供的宏会自动帮你处理这些问题. |
| 117 | +你唯一需要做的就是在你想要保留所有权的变量后面加上.iter() 或 使用 & , 其余会在宏内自动处理. |
| 118 | +But in this library, you don't need to do this, the provided macros will automatically handle these problems for you. |
| 119 | +You only need to add .iter() or use & before the variable you want to keep ownership, the rest will be automatically handled in the macro. |
| 120 | +```rust |
| 121 | +let vec_1 = vec!["ABC".to_string(), "DEF".to_string()]; |
| 122 | +let vec_2 = vec!["abc".to_string(), "def".to_string()]; |
| 123 | +let vec_3 = vec![123, 456]; |
| 124 | +let vec = vector![ |
| 125 | + (i.clone(),j.clone(),*k) |
| 126 | + for i in vec_1 if i == "ABC" |
| 127 | + for j in vec_2.iter() if j == "abc" |
| 128 | + // for j in &vec_2 if j == "abc" 这种写法也是可以的 this is also reasonable |
| 129 | + for k in vec_3 if k == &123 |
| 130 | +]; |
| 131 | +// println!("{:?}", vec_1); // borrow of moved value |
| 132 | +println!("{:?}", vec_2); // work well |
| 133 | +// println!("{:?}", vec_3); // borrow of moved value |
| 134 | +``` |
| 135 | + |
| 136 | +同时, 该库还支持键值对容器类型, HashMap, BTreeMap |
| 137 | +This library also supports key-value collection types, HashMap, BTreeMap |
| 138 | +```rust |
| 139 | +let vec_key = vec!["key_1".to_string(), "key_2".to_string(), "key_3".to_string()]; |
| 140 | + let vec_value = [1, 2, 3]; |
| 141 | + let hash_map = hash_map!{ |
| 142 | + key.clone() : *value // 三种键值对分隔符都支持 |
| 143 | + // key.clone() => *value |
| 144 | + // key.clone() , *value |
| 145 | + for key in vec_key |
| 146 | + for value in vec_value |
| 147 | + }; |
| 148 | + assert_eq!( |
| 149 | + hash_map, |
| 150 | + HashMap::from([ |
| 151 | + ("key_1".to_string(), 3), |
| 152 | + ("key_2".to_string(), 3), |
| 153 | + ("key_3".to_string(), 3) |
| 154 | + ]) |
| 155 | + ); |
| 156 | +``` |
| 157 | + |
| 158 | +该库也支持迭代器推导式, 但不同于上面的集合推导式, 该迭代器推导式是基于引用的, 所以不会消耗所有权. |
| 159 | +除此之外的写法与集合推导式完全相同. |
| 160 | +Iterator comprehension is also supported, but unlike the collection comprehension above, this iterator comprehension is based on references, so it will not consume ownership. |
| 161 | +```rust |
| 162 | +let vec_1 = ["123".to_string(), "456".to_string(), "789".to_string()]; |
| 163 | +let vec_2 = ["ABC".to_string(), "DEF".to_string(), "GHI".to_string()]; |
| 164 | + |
| 165 | +let mut result3 = iterator_ref![ |
| 166 | +(x.clone(), y.clone()) if x.contains("1") else (y.clone(), x.clone()) |
| 167 | +for x in vec_1 if x.contains("1") || x.contains("7") |
| 168 | +for i in 1..=2 |
| 169 | +for y in vec_2 if y.contains("D") || x.contains("3")]; |
| 170 | + |
| 171 | +for _ in 0..=9 { |
| 172 | + println!("{:?}", result3.next()); |
| 173 | +} |
| 174 | +/* |
| 175 | +Some(("123", "ABC")) |
| 176 | +Some(("123", "DEF")) |
| 177 | +Some(("123", "GHI")) |
| 178 | +Some(("123", "ABC")) |
| 179 | +Some(("123", "DEF")) |
| 180 | +Some(("123", "GHI")) |
| 181 | +Some(("789", "DEF")) |
| 182 | +Some(("789", "DEF")) |
| 183 | +None |
| 184 | +None |
| 185 | +*/ |
| 186 | +``` |
| 187 | + |
| 188 | +以上写法与下面的写法是完全的等价形式 |
| 189 | +The above writing is equivalent to the following writing |
| 190 | +```rust |
| 191 | +let vec_1 = ["123".to_string(), "456".to_string(), "789".to_string()]; |
| 192 | +let vec_2 = ["ABC".to_string(), "DEF".to_string(), "GHI".to_string()]; |
| 193 | + |
| 194 | +let mut result3 = { |
| 195 | + let vec_2 = vec_2.iter().collect::<Vec<_>>(); |
| 196 | + let vec_1 = vec_1.iter().collect::<Vec<_>>(); |
| 197 | + (vec_1) |
| 198 | + .into_iter() |
| 199 | + .filter_map(move |x| { |
| 200 | + (x.contains("1") || x.contains("7")) |
| 201 | + .then(|| { |
| 202 | + let vec_2 = vec_2.clone(); |
| 203 | + (1..=2) |
| 204 | + .into_iter() |
| 205 | + .filter_map(move |i| { |
| 206 | + (true) |
| 207 | + .then(|| { |
| 208 | + let vec_2 = vec_2.clone(); |
| 209 | + (vec_2) |
| 210 | + .into_iter() |
| 211 | + .filter_map(move |y| { |
| 212 | + (y.contains("D") || x.contains("3")) |
| 213 | + .then(|| { |
| 214 | + if x.contains("1") { |
| 215 | + (x.clone(), y.clone()) |
| 216 | + } else { |
| 217 | + (y.clone(), x.clone()) |
| 218 | + } |
| 219 | + }) |
| 220 | + }) |
| 221 | + }) |
| 222 | + }) |
| 223 | + }) |
| 224 | + }) |
| 225 | + .flatten() |
| 226 | + .flatten() |
| 227 | +}; |
| 228 | +``` |
| 229 | + |
| 230 | + |
| 231 | +# some details |
| 232 | + |
| 233 | +vector! : |
| 234 | + 使用push添加元素 |
| 235 | + use push to add elements |
| 236 | + |
| 237 | +vec_deque! : |
| 238 | + 使用push_back添加元素 |
| 239 | + use push_back to add elements |
| 240 | + |
| 241 | +linked_list! : |
| 242 | + 使用push_back添加元素 |
| 243 | + use push_back to add elements |
| 244 | + |
| 245 | +hash_set! : |
| 246 | + 使用insert添加元素 |
| 247 | + use insert to add elements |
| 248 | + |
| 249 | +hash_map! : |
| 250 | + 使用insert添加键值对 |
| 251 | + use insert to add key-value pairs |
| 252 | + |
| 253 | +b_tree_map! : |
| 254 | + 使用insert添加键值对 |
| 255 | + use insert to add key-value pairs |
| 256 | + |
| 257 | +b_tree_set! : |
| 258 | + 使用insert添加元素 |
| 259 | + use insert to add elements |
| 260 | + |
| 261 | +binary_heap! : |
| 262 | + 使用push添加元素 |
| 263 | + use push to add elements |
0 commit comments