Rust nested fors itering over the same vector - rust

I was trying to change some of vector elements, while itering over the vector.
for operator in operators {
// add left side
let node = nodes[operator.index-1].clone();
nodes[operator.index].children.push(node);
// add right side
let node = nodes[operator.index+1].clone();
nodes[operator.index].children.push(node);
// remove used nodes
nodes.remove(operator.index+1);
nodes.remove(operator.index-1);
// two items were removed, so every index higher than the current one needs to be lowered by 2
for operator2 in &mut operators {
if operator2.index > operator.index {
operator2.index -= 2;
}
}
}
Sadly this isn't possible in rust, because error says that 'operators' was moved. I tried to change for to look like this:
for operator in &operators, but then it has problem getting 'operators' as mutable and immutable at the same time. What can I do to make it work?

Use simple loops with indices:
for operator_idx in 0..operators.len() {
let operator = &operators[operator_idx];
// add left side
let node = nodes[operator.index-1].clone();
nodes[operator.index].children.push(node);
// add right side
let node = nodes[operator.index+1].clone();
nodes[operator.index].children.push(node);
// remove used nodes
nodes.remove(operator.index+1);
nodes.remove(operator.index-1);
// two items were removed, so every index higher than the current one needs to be lowered by 2
for operator2 in &mut operators {
if operator2.index > operator.index {
operator2.index -= 2;
}
}
}

Related

Rust lifetimes in if statement

I have an if statement in a for loop, and I want it to create a variable with the lifetime of that iteration of the for loop.
for condition_raw in conditions_arr {
println!("{}", condition_raw);
let matching = !condition_raw.contains('!');
if matching {
let index = condition_raw.find('=').unwrap_or_default();
} else {
let index = condition_raw.find('!').unwrap_or_default();
}
let key = &condition_raw[..index];
}
let key = &condition_raw[..index]; currently throws cannot find value index in this scope
not found in this scope rustc E0425
I'll ignore the condition variable which does not seem to be used at all in your example.
A let statement creates a binding that holds at most for the current scope. For this reason, when you create the index variable inside the if, you are not making it accessible anywhere else. There are two ways to solve this issue.
The first way is to explicitly declare index as being part of the outer scope, and only define it inside the if statement.
for condition_raw in conditions_arr {
let matching = !condition_raw.contains('!');
let index;
if matching {
index = condition_raw.find('=').unwrap_or_default();
} else {
index = condition_raw.find('!').unwrap_or_default();
}
let key = &condition_arr[..index];
}
There is no risk of accidentally not defining index, since Rust will make sure that index is defined (exactly once) in all possible branching of your code before it is used. Yet, it's not a pretty solution because it violates a "locality" principle, that is that pieces of code should have effects on or pieces of code that are sufficiently close. In this case, the let index; is not too far from its definition, but it could be arbitrarily far, which makes it painful for someone who reads your code to remember that there is a declared but not yet defined.
Alternatively, you could use the fact that most things in Rust are expressions:
for condition_raw in conditions_arr {
let matching = !condition_raw.contains('!');
let index = if matching {
condition_raw.find('=').unwrap_or_default();
} else {
condition_raw.find('!').unwrap_or_default();
}
let key = &condition_arr[..index];
}
But, in fact, you could factorize your code even more, which is usually better:
for condition_raw in conditions_arr {
let matching = !condition_raw.contains('!');
let index = condition_raw.find(if matching {
'='
} else {
'!'
}).unwrap_or_default();
let key = &condition_arr[..index];
Or, even more
for condition_raw in conditions_arr {
let index = condition_raw
.find('!')
.or_else(|| condition_raw.find('='))
.unwrap_or_default();
let key = &condition_arr[..index];
}
An idiomatic way to assign variables from an if else statement is as follows:
let index: usize = if matching {
condition_raw.find('=').unwrap_or_default()
} else {
condition_raw.find('!').unwrap_or_default()
};
Idiomatic way of assigning a value from an if else condition in Rust
In Rust, an if/else block is an expression. That is to say, the block itself has a value, equivalent to the last expression in whatever section was executed. With that in mind, I would structure your code like this:

Using while let with two variables simultaneously

I'm learning Rust and have been going through leetcode problems. One of them includes merging two linked lists, whose nodes are optional. I want to write a while loop that would go on until at least 1 node becomes None, and I was trying to use the while let loop for that.
However, it looks like the while let syntax supports only one optional, e.g.:
while let Some(n) = node {
// do stuff
}
but I can't write
while let Some(n1) = node1 && Some(n2) = node2 {
}
Am I misunderstanding the syntax? I know I can rewrite it with a while true loop, but is there a more elegant way of doing it?
Also, can one do multiple checks with if let? Like if let None=node1 && None=node2 {return}
You can pattern match with Option::zip:
while let Some((n1, n2)) = node1.zip(node2) {
...
}
In addition to what #Netwave said, on nightly you can use the unstable let_chains feature:
#![feature(let_chains)]
while let Some(n1) = node1 && let Some(n2) = node2 {
// ...
}

Issue when creating a Vector and assigning it later on [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
After reading a LOT of documentation I figured out that I am facing a problem of scope, but I have no idea how to solve it. See the example code below:
fn main() {
let mut bytes_buf:Vec<u8> = Vec::new(); // 1) where I declare the Vector, the compiler force me to initialize it.
loop {
match socket.recv_from(&mut buf) {
Ok((size, src)) => {
if count == 0 {
chunks_cnt = ...
bytes_buf = vec![0; MAX_CHUNK_SIZE * chunks_cnt as usize]; // 2) where I want to set vector size, only ONCE, and after knowing chunks_cnt
}
bytes_buf[start..end].copy_from_slice(buf); // 3) where I want to gradually fill the vector
}
}
}
}
For convenience, you can check the full code here
Possible solution
Here the socket fills the slice buf. If it fails an error message is shown. If is succeeds it will enter the loop.
On each iteration of the loop, the buf is converted to a Vec<u8> and appended to bytes_buf. Then if this is the first iteration, then the size value is inserted into the first position. Then the first flag is set to false. After that all iterations will continue appending data to the vector.
The following minimal example should compile fine:
use std::net::{UdpSocket};
const UDP_HEADER: usize = 8;
const IP_HEADER: usize = 20;
const MAX_DATA_LENGTH: usize = (64 * 1024 - 1) - UDP_HEADER - IP_HEADER;
fn main() {
let socket = UdpSocket::bind("0.0.0.0:8888").expect("Could not bind socket");
let mut buf= [0u8; MAX_DATA_LENGTH]; // Slice that will be filled by recv_from.
let mut bytes_buf:Vec<u8> = Vec::new(); // Vector where the data will be moved.
let mut first = true; // Flag that indicates if this is our first iteration.
loop {
match socket.recv_from(&mut buf) {
Ok((_size, _src)) => {
// Convert the slice to a vector (to_vec function) and append it to the bytes_buf.
bytes_buf.append(&mut buf.to_vec());
if first {
// Insert function inserts the element at the specified position and shifts
// all elements after it to the right.
bytes_buf.insert(0, 10u8); // IDK What value you need here.
}
first = false; // Set first to false
},
Err(err) => eprintln!("Error: {}", err) // If we fail display the error.
}
}
}
Side note
Your example was missing lots of variables and context. Despite this, I managed to create a minimal working example of what I believe you are trying to achieve thanks to the link you shared despite being quite different. Please next time provide a minimal reproducible example. More information here: How to create a Minimal, Reproducible Example
Have a nice day!

Do i have to create a copy of objects for threads need [duplicate]

This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed 1 year ago.
I created a two methods one synchronous and one with multiple threads because I wanted to compare performance synchronous and parallel method. But I am having a one issue every time when I want to use my data in threads I have to copy them first even if I know that they want to be dropped till the end of this method. If I do not copy this data before using in threads then I am getting an error that I have to make my data 'static:
fn parallel_kronecker_product(&self, matrix: &Matrix) -> Matrix {
let product_rows = self.rows_count * matrix.rows_count;
let product_columns_count = self.columns_count * matrix.columns_count;
let product = Arc::new(Mutex::new(Matrix::new_zeros_matrix(
product_rows,
product_columns_count,
)));
let mut handles = vec![];
for m1_row_index in 0..self.rows_count {
let product = Arc::clone(&product);
let matrix_a = self.to_owned();
let matrix_b = matrix.to_owned();
handles.push(
thread::spawn(move || {
for m1_column_index in 0..matrix_a.columns_count {
for m2_row_index in 0..matrix_b.rows_count {
for m2_column_index in 0..matrix_b.columns_count {
let product_row_index = m1_row_index * matrix_b.rows_count + m2_row_index;
let product_column_index =
m1_column_index * matrix_b.columns_count + m2_column_index;
let mut prod = product.lock().unwrap();
(*prod)[product_row_index][product_column_index] = matrix_a[m1_row_index]
[m1_column_index]
* matrix_b[m2_row_index][m2_column_index];
}
}
}
})
);
}
for handle in handles {
handle.join().unwrap();
}
return product.lock().unwrap().clone();
}
So here I have two matrices. Base which is immutable self and one from parameter matrix. Inside for m2_row_index in 0..matrix_b.rows_count loop I am only multiplying some data which doesn't change original data. Then I iterate over all threads to tell rust to wait until all threads finish their job, so nothing outside this method scope should drop this matrix
Can you tell me, what can I do to do not copy this data?
You can use a scoped thread from a third party crate. There are a few to choose from, but a popular one is from crossbeam. The reason this is needed is because the types used for threads spawned with std::thread::spawn do not carry information about how long they last, even if you are explicitly joining them. Crossbeam's scoped threads are bound to the lifetime of the surrounding Scope so the borrow checker can be sure that they are finished with borrowed data when the scope ends.
Your provided code has a lot of definitions missing, so I didn't try to compile it, but the general idea would be this:
fn parallel_kronecker_product(&self, matrix: &Matrix) -> Matrix {
// Create a new thread scope and make it own the locals
thread::scope(move |scope| {
let product_rows = self.rows_count * matrix.rows_count;
let product_columns_count = self.columns_count * matrix.columns_count;
let product = Arc::new(Mutex::new(Matrix::new_zeros_matrix(
product_rows,
product_columns_count,
)));
let mut handles = vec![];
for m1_row_index in 0..self.rows_count {
let product = Arc::clone(&product);
let matrix_a = self.to_owned();
let matrix_b = matrix.to_owned();
// spawn a new thread inside the scope which owns the data it needs to borrow
handles.push(scope.spawn(move |_| {
for m1_column_index in 0..matrix_a.columns_count {
for m2_row_index in 0..matrix_b.rows_count {
for m2_column_index in 0..matrix_b.columns_count {
let product_row_index =
m1_row_index * matrix_b.rows_count + m2_row_index;
let product_column_index =
m1_column_index * matrix_b.columns_count + m2_column_index;
let mut prod = product.lock().unwrap();
(*prod).ind();
}
}
}
}));
}
for handle in handles {
handle.join().unwrap();
}
// probably need a new local binding here. For... reasons...
let product = product.lock().unwrap().clone();
product
}).unwrap()
}

How to avoid memory leaks when building a slice of slices using ArrayLists

I'm trying to build a slice of slices using multiple std.ArrayLists.
The code below works, but the memory allocator std.testing.allocator warns me of a memory leaks wherever I append new elements to a sublist.
const std = #import("std");
const mem = std.mem;
fn sliceOfSlices(allocator: *mem.Allocator) ![][]usize {
var list = std.ArrayList([]usize).init(allocator);
var i: usize = 0;
while (i < 3) : (i += 1) {
var sublist = std.ArrayList(usize).init(allocator);
// errdefer sublist.deinit(); // here?
var n: usize = 0;
while (n < 5) : (n += 1) {
try sublist.append(n); // leaks
// errdefer sublist.deinit(); // here?
// errdefer allocator.free(sublist.items);
}
try list.append(sublist.toOwnedSlice());
}
return list.toOwnedSlice();
}
const testing = std.testing;
test "memory leaks" {
const slice = try sliceOfSlices(testing.allocator);
testing.expectEqual(#intCast(usize, 3), slice.len);
testing.expectEqual(#intCast(usize, 5), slice[0].len);
}
I tried to use errdefer in several places to free the allocated sublist, but it didn't work. From the documentation it seems a lifetime issue, but I'm not sure how to handle it.
the std.ArrayList(T).items slice has a lifetime that remains valid until the next time the list is resized, such as by appending new elements.
— https://ziglang.org/documentation/master/#Lifetime-and-Ownership
What's the appropriate error handling when list.append() fails?
I am a beginner to zig so perhaps I am totally wrong here, but I think the reason why you are getting the memory leak is not because something failed!
As you use ArrayList its memory is allocated via an allocator, the memory has explicitly to be freed at end of usage. For an ArrayList you could simply use the deinit() function. However as your function sliceOfSlices() converts that ArrayList wrapper to a slice, you have to use testing.allocator.free(slice) to get rid of the memory used by that slice.
But note: every element of your slice is itself a slice (or a pointer to it). Also obtained via ArrayList.toOwnedSlice(). Therefore those slices you have also to get rid of, before you can deallocate the containing slice.
So I would change your test to
test "memory leaks" {
const slice = try sliceOfSlices(testing.allocator);
defer {
for (slice) |v| {
testing.allocator.free(v);
}
testing.allocator.free(slice);
}
testing.expectEqual(#intCast(usize, 3), slice.len);
testing.expectEqual(#intCast(usize, 5), slice[0].len);
}
and now no memory leak should occur anymore.
Perhaps somebody knows a better solution, but lacking experience here, this would be the way to go, IMO.
And after some thinking, answering your question what to do in case of an error, I would rewrite your function sliceOfSlices() to
fn sliceOfSlices(allocator: *mem.Allocator) ![][]usize {
var list = std.ArrayList([]usize).init(allocator);
errdefer {
for (list.items) |slice| {
allocator.free(slice);
}
list.deinit();
}
var i: usize = 0;
while (i < 3) : (i += 1) {
var sublist = std.ArrayList(usize).init(allocator);
errdefer sublist.deinit();
var n: usize = 0;
while (n < 5) : (n += 1) {
try sublist.append(n);
}
try list.append(sublist.toOwnedSlice());
}
return list.toOwnedSlice();
}
Now if any error happened in your function, both list and sublist should be cleaned up properly. Still if no error was returned from the function, your calling code would be responsible for the cleanup to avoid memory leaks like implemented in the test block above.

Resources