<-- Home
|--rust
略微变态的
使用
For Else Loop in Rust如何实现for-else语法
形而下之,下不为例
Rust中有没有for-else语法?
答案是,没有。
但是,我们可以通过一些方法来实现for-else语法。
各种实现方式
使用标志位
1let mut found = false;
2for i in 0..10 {
3 if i == 15 {
4 found = true;
5 break;
6 }
7}
8if !found {
9 println!("Not found");
10}
这个思路非常简单,循环,如果没有找到,就执行else块。
if
特殊用法
1if 'search: loop {
2 for i in 0..10 {
3 if i == 15 {
4 break 'search false;
5 }
6 }
7 true
8} {
9 println!("Not found");
10}
这个是在耍赖,if后面是一个语句
1'search: loop {
2 for i in 0..10 {
3 if i == 15 {
4 break 'search false;
5 }
6 }
7 true
8}
这个loop表达式返回一个布尔值,如果找到,返回false,否则返回true。
函数式
10..10.iter()
2 .find(|&i| i == 15)
3 .or_else(|| println!("Not found"));
这个是函数式的实现,使用find
方法,如果找到,返回Some(i),否则返回None。这个归根结底使用了Option
类型。
略微变态的if let
1if let None = (0..10).find(|&i| i == 15) {
2 println!("Not found");
3}
这个是略微变态的实现,使用if let
语句,如果找到,返回Some(i)。后面还可以加个else块,如果找到了,就执行else块。
使用label
语句块
1'label: {
2 for i in 0..10 {
3 if i == 15 {
4 break 'label false;
5 }
6 }
7 println!("Not found");
8}
这个是使用label
语句块的实现,如果找到,就执行break
语句,否则执行println!("Not found")
语句。
说在最后
其实,Rust中没有for-else语法。上面这些都是一些奇技淫巧,用来实现for-else语法。没有任何意义,最好就是写点最平实无华的代码。
好吧,我们其实还能写一个宏来实现for-else语法。
1//! A macro that provides a for-else control structure in Rust.
2//!
3//! This macro allows you to execute code in an else block when a for loop completes without breaking.
4//! It's similar to Python's for-else construct.
5//!
6//! # Examples
7//!
8//! ```rust
9//! use forelse::for_else;
10//!
11//! let mut found = false;
12//! for_else!(x in 1..=5 => {
13//! if x == 3 {
14//! println!("Found 3");
15//! found = true;
16//! }
17//! } else {
18//! println!("Not found");
19//! });
20//! ```
21//!
22//! The else block will execute if the loop completes without breaking.
23//! This is useful for search operations where you want to handle both found and not found cases.
24
25use quote::quote;
26use syn::{parse_macro_input, Expr, Block, Pat};
27
28/// The main macro that implements the for-else control structure.
29///
30/// # Syntax
31///
32/// ```rust
33/// use forelse::for_else;
34///
35/// for_else!(x in 1..=5 => {
36/// // loop body
37/// } else {
38/// // else body
39/// });
40/// ```
41///
42/// The else block will execute if the loop completes without breaking.
43#[proc_macro]
44pub fn for_else(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
45 let input = parse_macro_input!(input as ForElseInput);
46
47 let pattern = input.pattern;
48 let range = input.range;
49 let body = input.body;
50 let else_body = input.else_body;
51
52 let expanded = quote! {
53 {
54 let mut executed = false;
55 {
56 'for_else: for #pattern in #range {
57 executed = true;
58 #body
59 }
60 }
61 if !executed {
62 #else_body
63 }
64 }
65 };
66
67 proc_macro::TokenStream::from(expanded)
68}
69
70/// Internal structure to parse the macro input
71struct ForElseInput {
72 pattern: Pat,
73 range: Expr,
74 body: Block,
75 else_body: Block,
76}
77
78impl syn::parse::Parse for ForElseInput {
79 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
80 let pattern = Pat::parse_single(input)?;
81 input.parse::<syn::Token![in]>()?;
82 let range = Expr::parse(input)?;
83 input.parse::<syn::Token![=>]>()?;
84 let body = Block::parse(input)?;
85 input.parse::<syn::Token![else]>()?;
86 let else_body = Block::parse(input)?;
87
88 Ok(ForElseInput {
89 pattern,
90 range,
91 body,
92 else_body,
93 })
94 }
95}
测试的代码:
1use forelse::for_else;
2
3/// Basic tests for the for-else macro
4mod basic {
5 use super::*;
6
7 /// Test finding an element in a range
8 #[test]
9 fn test_find_in_range() {
10 let mut found = false;
11 for_else!(x in 1..=5 => {
12 if x == 3 {
13 println!("Found 3");
14 found = true;
15 }
16 } else {
17 panic!("Should not reach else branch");
18 });
19 assert!(found);
20 }
21
22 /// Test not finding an element in a range
23 #[test]
24 fn test_not_find_in_range() {
25 let mut found = false;
26 for_else!(x in 1..=5 => {
27 if x == 6 {
28 println!("Found 6");
29 found = true;
30 }
31 } else {
32 println!("Not found");
33 });
34 assert!(!found);
35 }
36
37 /// Test with an empty range
38 #[test]
39 fn test_empty_range() {
40 let mut found = false;
41 for_else!(x in 1..1 => {
42 println!("Found {}", x);
43 found = true;
44 } else {
45 println!("Empty range");
46 });
47 assert!(!found);
48 }
49}
50
51/// Tests for control flow statements
52mod control_flow {
53 use super::*;
54
55 /// Test with break statement
56 #[test]
57 fn test_break() {
58 let mut found = false;
59 for_else!(x in 1..=5 => {
60 if x == 3 {
61 break;
62 }
63 } else {
64 println!("Not found");
65 });
66 assert!(!found);
67 }
68
69 /// Test with continue statement
70 #[test]
71 fn test_continue() {
72 let mut found = false;
73 for_else!(x in 1..=5 => {
74 if x == 3 {
75 continue;
76 }
77 found = true;
78 } else {
79 panic!("Should not reach else branch");
80 });
81 assert!(found);
82 }
83}
84
85/// Tests for different iterator types
86mod iterators {
87 use super::*;
88
89 /// Test with complex pattern matching
90 #[test]
91 fn test_tuple_iteration() {
92 let mut found = false;
93 for_else!((x, y) in [(1, 2), (3, 4), (5, 6)].iter() => {
94 if x == &3 && y == &4 {
95 println!("Found ({}, {})", x, y);
96 found = true;
97 }
98 } else {
99 panic!("Should not reach else branch");
100 });
101 assert!(found);
102 }
103
104 /// Test with string iteration
105 #[test]
106 fn test_string_iteration() {
107 let mut found = false;
108 for_else!(c in "hello".chars() => {
109 if c == 'e' {
110 println!("Found 'e'");
111 found = true;
112 }
113 } else {
114 panic!("Should not reach else branch");
115 });
116 assert!(found);
117 }
118}
119
120/// Tests for fallible types (Option and Result)
121mod fallible {
122 use super::*;
123
124 /// Test with Some variant
125 #[test]
126 fn test_some_iteration() {
127 let mut found = false;
128 for_else!(x in Some(42) => {
129 if x == 42 {
130 println!("Found 42");
131 found = true;
132 }
133 } else {
134 panic!("Should not reach else branch");
135 });
136 assert!(found);
137 }
138
139 /// Test with None variant
140 #[test]
141 fn test_none_iteration() {
142 let mut found = false;
143 for_else!(x in None::<i32> => {
144 println!("Found {}", x);
145 found = true;
146 } else {
147 println!("None case");
148 });
149 assert!(!found);
150 }
151
152 /// Test with Ok variant
153 #[test]
154 fn test_ok_iteration() {
155 let mut found = false;
156 for_else!(x in Ok::<i32, &str>(42) => {
157 if x == 42 {
158 println!("Found 42");
159 found = true;
160 }
161 } else {
162 panic!("Should not reach else branch");
163 });
164 assert!(found);
165 }
166
167 /// Test with Err variant
168 #[test]
169 fn test_err_iteration() {
170 let mut found = false;
171 for_else!(x in Err::<i32, &str>("error") => {
172 println!("Found {}", x);
173 found = true;
174 } else {
175 println!("Error case");
176 });
177 assert!(!found);
178 }
179}
不知道这样行不行,当然,还是难看……
工程文件什么的:
结论
这还啥结论,Python程序员就不能问这样的问题,有且只有一种正确的方式编程是Python程序员的最大、唯一、不多的美德……
文章标签
|-->rust |-->for-else |-->loop |-->macro
- 本站总访问量:次
- 本站总访客数:人
- 可通过邮件联系作者:Email大福
- 也可以访问技术博客:大福是小强
- 也可以在知乎搞抽象:知乎-大福
- Comments, requests, and/or opinions go to: Github Repository