I've got code to write where there is a common idiom where I have a Vec<f64> and I have to perform some arithmetic on it.
Sometimes I want to modify the Vec in place, and other times I want to create new Vec with the results of the operation.
What is the idiomatic way to do each of these in Rust?
Modify in place:
fn main() {
let mut data: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
for el in &mut data {
*el *= 2.0;
}
println!("{:?}", data);
}
[2.0, 4.0, 6.0, 8.0]
Create a new Vec with the results:
fn main() {
let data: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
let results: Vec<f64> = data.iter().map(|el| el * 2.0).collect();
println!("Original: {:?}", data);
println!("Results: {:?}", results);
}
Original: [1.0, 2.0, 3.0, 4.0]
Results: [2.0, 4.0, 6.0, 8.0]
Background
for el in &mut data iterates over data mutably without consuming it. el is a &mut f64 that directly references the item in the vector; modifying it directly modifies the vector content.
data.iter() creates an iterator over the elements of data without consuming data. .map() then applies an operation to each element and returns a new iterator over the results. .collect() then consumes all elements of the iterator and collects it into whatever it's supposed to create; in this case a Vec<f64> due to the type annotation after results. The pattern .iter().map().collect() is fairly common in Rust and is worth being remembered.
Related
I am learning rust, Run the following code.
I want to change each value of the array
use rand::Rng;
// fn main() {
// let mut x: [i32; 30] = [1; 30];
// for (index, value) in x.iter().enumerate() {
// // no worker
// x[index] = rand::thread_rng().gen_range(1..100);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `x[_]` occurs here
// println!("{}", x[index]);
// }
// }
fn main() {
let mut x = [1; 30];
let enumerate = x.iter().enumerate();
for index in 0..x.len() {
// worker!
x[index] = rand::thread_rng().gen_range(1..100);
println!("{}", x[index]);
}
}
I want to know why
The error is happening because the code is trying to modify an array while it's being used by an iterator. To fix this, you need to use an iterator that allows you to modify the array.
In Rust, there's a distinction between iter() and iter_mut(). iter() returns an iterator that gives you read-only access to the elements of an array, while iter_mut() returns an iterator that gives you mutable access to the elements of an array.
So, in your code, instead of using x.iter().enumerate(), you can use x.iter_mut().enumerate() to get an iterator that lets you modify the elements of x:
use rand::Rng;
fn main() {
let mut x: [i32; 30] = [1; 30];
for (_, value) in x.iter_mut().enumerate() {
*value = rand::thread_rng().gen_range(1..100);
println!("{}", *value);
}
}
I've go a lot of unit tests to write which rely on lists of complex numbers. (Crate num-complex = "0.4.0").
I'd like to be able to initialize Vecs of Complex<F:Float> with as little boilerplate as possible.
I was thinking it could be like the vec![] macro except a bit more specialized, i.e. that it would consume tuples of Float and return a Vec<Complex<f64>>. I suppose the syntax would be like:
let v: Vec<Complex<f64>> = vec_cplx![(0.0,-25.0), (0.0, -9.0)]
It would be nice if the Float type were generic, but not really necessary since I use only f64s at the moment.
You can write it like this:
use num::Complex;
macro_rules! vec_cplx {
($(($re:expr, $im:expr)),*) => {
vec![$(Complex::new($re, $im)),*]
}
}
fn main() {
let v: Vec<Complex<f32>> = vec_cplx![(0.0, -25.0), (0.0, -9.0)];
dbg!(v);
let v: Vec<Complex<f64>> = vec_cplx![(0.0, -25.0), (0.0, -9.0)];
dbg!(v);
}
Playground
This will work with any type that Complex::new() accepts since it's a macro and the type checking happens after macro expansion.
Are you certain you need a dedicated macro?
I would simply map and collect a literal array of tuples.
Or maybe a function doing so would be sufficient?
use num_complex::Complex;
use num_traits::float::Float;
fn vec_cplx<F: Float, const N: usize>(
tuples: [(F, F); N]
) -> Vec<Complex<F>> {
tuples
.into_iter()
.map(|(re, im)| Complex { re, im })
.collect()
}
fn main() {
let v1_f64: Vec<Complex<f64>> = [(1.1, 2.2), (3.3, 4.4), (5.5, 6.6)]
.into_iter()
.map(|(re, im)| Complex { re, im })
.collect();
println!("{:?}", v1_f64);
//
let v1_f32: Vec<Complex<f32>> = [(1.1, 2.2), (3.3, 4.4), (5.5, 6.6)]
.into_iter()
.map(|(re, im)| Complex { re, im })
.collect();
println!("{:?}", v1_f32);
//
let v2_f64: Vec<Complex<f64>> =
vec_cplx([(1.1, 2.2), (3.3, 4.4), (5.5, 6.6)]);
println!("{:?}", v2_f64);
//
let v2_f32: Vec<Complex<f32>> =
vec_cplx([(1.1, 2.2), (3.3, 4.4), (5.5, 6.6)]);
println!("{:?}", v2_f32);
}
Iterators is consumed by map, so require cloned(equals to clone?) when mapping a iterator multiple times. I have following code:
fn main() {
let a: Vec<(&str, (&i32, &i32))> = vec![("0", (&0, &1)), ("1", (&2, &3))];
let iter = a.iter().map(|x| x.1 as (&i32, &i32));
// occur clone process on i32?
let xs: Vec<&i32> = iter.cloned().map(|(x, _)| x).collect();
let ys: Vec<&i32> = iter.map(|(_, y)| y).collect();
println!("{:?}", xs);
println!("{:?}", ys);
}
The problem is that cloned method probably deep copy whole an iterated element even though the elements contain immutable references. Cloned elements is i32 in above, but it may actually have big structure. I want to explicitly shallow copy elements which contain references to i32 (actually bigger struct) when branch iterator iter. Is it possible?
Use clone instead of cloned:
fn main() {
let a: Vec<(&str, (&i32, &i32))> = vec![("0", (&0, &1)), ("1", (&2, &3))];
let iter = a.iter().map(|x| x.1 as (&i32, &i32));
// occur clone process on i32?
let xs: Vec<&i32> = iter.clone().map(|(x, _)| x).collect();
let ys: Vec<&i32> = iter.map(|(_, y)| y).collect();
println!("{:?}", xs);
println!("{:?}", ys);
}
Playground
clone clones the iterator itself. Meanwhile cloned clones the underlying elements, from the documentation:
Cloned: An iterator that clones the elements of an underlying iterator.
So, I have the following code successfully performing filter in vector:
let mut v1 : Vec<i32> = vec!(1,2,3);
let v2 : Vec<&mut i32> = v1.iter_mut().filter(|x| {**x == 2}).collect();
println!("{:?}", v2);
Since the type signature of the predicate in the filter function is
FnMut(&Self::Item) -> bool, I was assuming that that mutation inside
the closure will work:
let mut v1 : Vec<i32> = vec!(1,2,3);
let v2 : Vec<&mut i32> = v1.iter_mut().filter(|x| {**x = 3; **x == 2}).collect();
println!("{:?}", v2);
But the above code results in a compile error. How to fix that ? Note
that I'm playing with rust to get a better understanding, so the abpve
example doesn't make sense (usually, nobody will try to mutate
things inside filter).
You are confusing two concepts: FnMut means that a function can change its captured variables, like:
fn main() {
let v1 = vec![1, 2, 3];
let mut i = 0usize;
let v2: Vec<_> = v1
.into_iter()
.filter(|x| {
i = i + 1;
*x == 2
})
.collect();
println!("We iterate {} times and produce {:?}", i, v2);
}
This doesn't mean that every parameter of a function will be mutable.
In your code, filter() takes a &Self::Item, which is very different from the map() one that takes Self::Item. Because the real type will translate to Map<Item=&mut i32> and Filter<Item=&&mut i32>. Rust forbids you from mutating a reference if it's behind a non mutable reference:
fn test(a: &&mut i32) {
**a = 5;
}
error[E0594]: cannot assign to `**a` which is behind a `&` reference
This is because Rust follows the the-rules-of-references:
At any given time, you can have either one mutable reference or any number of immutable references.
References must always be valid.
This means you can have more than one &&mut but only one &mut &mut. If Rust didn't stop you, you could mutate a &&mut and that would poison any other &&mut.
Unfortunately the full error description of E0594 is still not available, see #61137.
Note: Avoid side effects when you use the iterator API, I think it's OK to mutate your FnMut state but not the item, you should do this in a for loop, like:
fn main() {
let mut v1 = vec![1, 2, 3];
for x in v1.iter_mut().filter(|x| **x == 2) {
*x = 1;
}
println!("{:?}", v1);
}
I am trying to implement Karger's algorithm in Rust and I have run into an issue while trying to update a mutable hashmap in a while loop.
The map is updated successfully, but then in the next iteration when it was cloned, the values that were updated don't seem to have been changed. However removing elements from the map is reflected on later iterations.
I have tried debugging and printing the values of the map, but the sequence of events doesn't make sense to me.
use itertools::Itertools; // 0.8.0
use rand::seq::{IteratorRandom, SliceRandom}; // 0.6.5
use std::collections::HashMap;
fn contract_edge(graph: &mut HashMap<i32, Vec<i32>>, num_trials: i32) {
let mut count = 0;
while graph.len() > 2 && count < num_trials {
// clone graph so I can mutate graph later
let imut_graph = graph.clone();
// choose random node
let from_value = imut_graph
.keys()
.choose(&mut rand::thread_rng())
.unwrap()
.clone();
let values = imut_graph.get(&from_value);
let to_value = values
.unwrap()
.choose(&mut rand::thread_rng())
.unwrap()
.clone();
let from_edges = imut_graph[&from_value].iter().clone();
// accessing to_value in imut_graph gives error here later
let to_edges = imut_graph[&to_value]
.iter()
.clone()
.filter(|&x| *x != from_value && *x != to_value);
let new_edges = from_edges.chain(to_edges);
// since I am mutating the graph I thought the next time is is clone it would be updated?
graph.insert(from_value, new_edges.map(|v| v.clone()).collect());
graph.remove(&to_value);
for (_key, val) in graph.iter_mut() {
*val = val
.iter()
.map(|v| if v == &to_value { &from_value } else { v })
.unique()
.cloned()
.collect();
}
count += 1;
}
}
When I try to access the map, I get element not found error, but the keys which have been removed should not exist in the vector values at that point.
I am convinced this is something I don't understand about (Im)mutability in Rust.
I'm not really sure what you are trying to achieve here, but based on what I can see above, that is, you'd like to mutate your original graph (because you are passing that as a mutable borrow to your function) and that you don't have a return value, and that your question is about mutating a hashmap -- I assume that you'd like the changes to be reflected in your original HashMap. So why are you cloning it in the first place then?
If on the other hand you don't want to mutate your original object, then don't pass it in as a mutable borrow, but as an immutable one. Then create a clone of it before you start the loop and use that cloned version throughout your algorithm.
The problem you are facing with is happening because on every iteration you are cloning the original graph and not your cloned imut_graph, i.e. on every iteration you create a new HashMap, which then you are mutating, then you start a new cycle and you are still checking the length of the original one and then you clone the original one again.
So the two options you have are:
use std::collections::HashMap;
fn mutated(map: &mut HashMap<i32, Vec<i32>>) {
map.insert(1, vec![4, 5, 6]);
}
fn cloned(map: &HashMap<i32, Vec<i32>>) -> HashMap<i32, Vec<i32>> {
let mut map = map.clone();
map.insert(2, vec![7, 8, 9]);
map
}
fn main() {
let mut map = HashMap::new();
map.insert(0, vec![1, 2, 3]);
println!("{:?}", cloned(&map));
mutated(&mut map);
println!("{:?}", map);
}
Which will give you:
{0: [1, 2, 3], 2: [7, 8, 9]}
{0: [1, 2, 3], 1: [4, 5, 6]}