Search code examples
for-looprustmutableborrowing

How can I fix these two for loops to allow modification of the vector content?


I'm trying to make a loop over the matrix made using a Vec<f64> inside a Vec, and then alter its elements one by one.

I cannot seem to make it work; I'm still too confused about the syntax...

extern crate rand;

use std::ptr;
use std::mem;

use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let mut v: Vec<Vec<f64>> = Vec::new();
    v.push(vec![0f64; 35]);
    v.push(vec![0f64; 35]);
    v.push(vec![0f64; 35]);
    v.push(vec![0f64; 35]);

    let len = v.len();
    for &el in &v {
        for q in &mut el {
            q = rng.gen::<f64>();
            println!("{}", q);
        }
        println!("{:?}", el);
    }
    println!("float: {}", rng.gen::<f64>());
    //println!("vec: {:?}, len: {}",v,len);
}

The compiler says this:

error[E0308]: mismatched types
  --> src/main.rs:19:17
   |
19 |             q = rng.gen::<f64>();
   |                 ^^^^^^^^^^^^^^^^ expected &mut f64, found f64
   |
   = note: expected type `&mut f64`
              found type `f64`
   = help: try with `&mut rng.gen::<f64>()`

I tried following the compiler hints, various combinations of mut & and .iter() or .iter_mut(), but none of them worked. After some frustration, I noticed that my search for a solution had become a Monte Carlo algorithm.


Solution

  • Read the error messages — they are a huge benefit of a statically typed language, but it does require you to actually look at them.

      --> src/main.rs:19:17
       |
    19 |             q = rng.gen::<f64>();
       |                 ^^^^^^^^^^^^^^^^ expected &mut f64, found f64
       |
       = note: expected type `&mut f64`
                  found type `f64`
       = help: try with `&mut rng.gen::<f64>()`
    

    Unfortunately, the "help" here isn't the right path, but it's just a guess from the compiler.

    You are attempting to create a random value of type f64 and assign it to a variable that holds a &mut f64. These are different types, so you get an error.

    You need to dereference the variable to store into it:

    extern crate rand;
    
    use rand::Rng;
    
    fn main() {
        let mut rng = rand::thread_rng();
    
        let mut v = vec![
            vec![0f64; 35],
            vec![0f64; 35],
            vec![0f64; 35],
            vec![0f64; 35],
        ];
    
        for el in &mut v {
            for q in el {
                *q = rng.gen::<f64>();
            }   
        }
    
        println!("vec: {:?}", v);
    }
    

    I'd probably not zero-initialize anything though, and write it as

    let mut rng = rand::thread_rng();
    
    let v: Vec<Vec<f64>> = (0..4)
        .map(|_| (0..35).map(|_| rng.gen()).collect())
        .collect();
    
    println!("vec: {:?}", v);