- Learning Rust
- Paul Johnson Vesa Kaihlavirta
- 1168字
- 2021-07-02 23:07:24
Using loop labels
Rust allows us to label our loops. This can be very useful, for example with nested loops. These labels act as symbolic names for the loop and as we have a name for the loop, we can instruct the application to perform a task on that name.
Consider the following simple example:
// 04/looplabels/src/main.rs
fn main() { 'outer_loop: for x in 0..10 { 'inner_loop: for y in 0..10 { if x % 2 == 0 { continue 'outer_loop; } if y % 2 == 0 { continue 'inner_loop; } println!("x: {}, y: {}", x, y); } } }
What will this code do?
Here, x % 2 == 0 (or y % 2 == 0) means that if a variable pided by two returns no remainder, then the condition is met and it executes the code in the braces. When x % 2 == 0, or when the value of the loop is an even number, we will tell the application to skip to the next iteration of outer_loop, which is an odd number. However, we will also have an inner loop. Again, when y % 2 is an even value, we will tell the application to skip to the next iteration of inner_loop.
In this case, the application will output the following results:

While this example may seem very simple, it does allow for a great deal of speed when checking data. Let's go back to our previous example of data being sent to the web service. Recall that we have two values—the recorded data and some other value; for ease, it will be a data point. Each data point is recorded 0.2 seconds apart; therefore, every fifth data point is one second.
This time, we want all of the values where the data is greater than 1.5 and the associated time of that data point, but only on a time when it's dead on a second. As we want the code to be understandable and human-readable, we can use a loop label on each loop.
The following code is not quite correct. Can you spot why? The code compiles as follows:
// 04/looplabels-2/src/main.rs
fn main() { let my_array = vec![0.6f32, 0.4, 0.2, 0.8, 1.3, 1.1, 1.7, 1.9, 1.3, 0.1, 1.6, 0.6, 0.9, 1.1, 1.31, 1.49, 1.5, 0.7]; let my_time = vec![0.2f32, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8]; 'time_loop: for(_, time_value) in my_time.iter().enumerate() { 'data_loop: for(_, value) in my_array.iter().enumerate() { if *value < 1.5 { continue 'data_loop; } if *time_value % 5f32 == 0f32 { continue 'time_loop; } println!("Data point = {} at time {}s", *value, *time_value); } } }
This example is a very good one to demonstrate the correct operator in use. The issue is the if *time_value % 5f32 == 0f32 line. We are taking a float value and using the modulus of another float to see whether we end up with 0 as a float.
Comparing any value that is not a string, int, long, or bool type to another is never a good plan, especially if the value is returned by some form of calculation. We can also not simply use continue on the time loop, so how can we solve this problem?
If you recall, we're using _ instead of a named parameter for the enumeration of the loop. These values are always an integer; therefore, if we replace _ for a variable name, then we can use % 5 to perform the calculation and the code becomes the following:
'time_loop: for(time_enum, time_value) in my_time.iter().enumerate() { 'data_loop: for(_, value) in my_array.iter().enumerate() { if *value < 1.5 { continue 'data_loop; } if time_enum % 5 == 0 { continue 'time_loop; } println!("Data point = {} at time {}s", *value, *time_value); } }
The next problem is that the output isn't correct. The code gives the following:
Data point = 1.7 at time 0.4s Data point = 1.9 at time 0.4s Data point = 1.6 at time 0.4s Data point = 1.5 at time 0.4s Data point = 1.7 at time 0.6s Data point = 1.9 at time 0.6s Data point = 1.6 at time 0.6s Data point = 1.5 at time 0.6s
The data point is correct, but the time is way out and continually repeats. We still need the continue statement for the data point step, but the time step is incorrect. There are a couple of solutions, but possibly the simplest will be to store the data and the time in a new vector and then display that data at the end.
The following code gets closer to what is required:
// 04/looplabels-3/src/main.rs
fn main() { let my_array = vec![0.6f32, 0.4, 0.2, 0.8, 1.3, 1.1, 1.7, 1.9, 1.3, 0.1, 1.6, 0.6, 0.9, 1.1, 1.31, 1.49, 1.5, 0.7]; let my_time = vec![0.2f32, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8]; let mut my_new_array = vec![]; let mut my_new_time = vec![]; 'time_loop: for(t, _) in my_time.iter().enumerate() { 'data_loop: for(v, value) in my_array.iter().enumerate() { if *value < 1.5 { continue 'data_loop; } else { if t % 5 != 0 { my_new_array.push(*value); my_new_time.push(my_time[v]); } } if v == my_array.len() { break; } } } for(m, my_data) in my_new_array.iter().enumerate() { println!("Data = {} at time {}", *my_data, my_new_time[m]); } }
We will now get the following output:
Data = 1.7 at time 1.4 Data = 1.9 at time 1.6 Data = 1.6 at time 2.2 Data = 1.5 at time 3.4 Data = 1.7 at time 1.4
Yes, we now have the correct data, but the time starts again. We're close, but it's not right yet. We aren't continuing the time_loop loop and we will also need to introduce a break statement. To trigger the break, we will create a new variable called done. When v, the enumerator for my_array, reaches the length of the vector (this is the number of elements in the vector), we will change this from false to true. This is then tested outside of the data_loop. If done == true, break out of the loop.
The final version of the code is as follows:
// 04/dataloop/src/main.rs
fn main() { let my_array = vec![0.6f32, 0.4, 0.2, 0.8, 1.3, 1.1, 1.7, 1.9, 1.3, 0.1, 1.6, 0.6, 0.9, 1.1, 1.31, 1.49, 1.5, 0.7]; let my_time = vec![0.2f32, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6]; let mut my_new_array = vec![]; let mut my_new_time = vec![]; let mut done = false; 'time_loop: for(t, _) in my_time.iter().enumerate() { 'data_loop: for(v, value) in my_array.iter().enumerate() { if v == my_array.len() - 1 { done = true; } if *value < 1.5 { continue 'data_loop; } else { if t % 5 != 0 { my_new_array.push(*value); my_new_time.push(my_time[v]); } else { continue 'time_loop; } } } if done {break;} } for(m, my_data) in my_new_array.iter().enumerate() { println!("Data = {} at time {}", *my_data, my_new_time[m]); } }
Our final output from the code is this:

- Getting Started with Gulp(Second Edition)
- Mastering Zabbix(Second Edition)
- Photoshop智能手機APP UI設計之道
- Python數據可視化:基于Bokeh的可視化繪圖
- Python神經網絡項目實戰
- Learning Data Mining with R
- Advanced Oracle PL/SQL Developer's Guide(Second Edition)
- HTML5從入門到精通(第4版)
- Building Wireless Sensor Networks Using Arduino
- 用Go語言自制編譯器
- 深度學習:基于Python語言和TensorFlow平臺(視頻講解版)
- PHP高性能開發:基礎、框架與項目實戰
- Learning Java Lambdas
- Learning ClojureScript
- Mastering Social Media Mining with R