ArtableBOX
ArtableBOX

Reputation: 25

Accessing Vector elements gives me an error Rust

I trying to write a program that will find the median of any given list.

Eventually, In the FINAL FINAL stretch, an error was shot into my face.

I tried to access elements of a Vector through a variable.

Take a look at the calc_med() function.

use std::io;
use std::sync::Mutex;

#[macro_use]
extern crate lazy_static;

lazy_static! {
    static ref num_list: Mutex<Vec<f64>> = Mutex::new(Vec::new());
}

fn main() {
    loop {
        println!("Enter: ");

        let mut inp: String = String::new();

        io::stdin().read_line(&mut inp).expect("Failure");

        let upd_inp: f64 = match inp.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                if inp.trim() == String::from("q") {
                    break;
                } else if inp.trim() == String::from("d") {
                    break {
                        println!("Done!");
                        calc_med();
                    };
                } else {
                    continue;
                }
            }
        };

        num_list.lock().unwrap().push(upd_inp);
        num_list
            .lock()
            .unwrap()
            .sort_by(|a, b| a.partial_cmp(b).unwrap());

        println!("{:?}", num_list.lock().unwrap());
    }
}

fn calc_med() {
    // FOR THE ATTENTION OF STACKOVERFLOW
    let n: f64 = ((num_list.lock().unwrap().len()) as f64 + 1.0) / 2.0;

    if n.fract() == 0.0 {
        let n2: usize = n as usize;
    } else {
        let n3: u64 = n.round() as u64;
        let n4: usize = n3 as usize;

        let median: f64 = (num_list[n4] + num_list[n4 - 1]) / 2;
        println!("{}", median);
    }
}

The error is as following:

   Compiling FindTheMedian v0.1.0 (/home/isaak/Documents/Code/Rusty/FindTheMedian)
error[E0608]: cannot index into a value of type `num_list`
  --> src/main.rs:50:28
   |
50 |         let median: f64 = (num_list[n4] + num_list[n4 - 1]) / 2;
   |                            ^^^^^^^^^^^^

error[E0608]: cannot index into a value of type `num_list`
  --> src/main.rs:50:43
   |
50 |         let median: f64 = (num_list[n4] + num_list[n4 - 1]) / 2;
   |                                           ^^^^^^^^^^^^^^^^

Upvotes: 0

Views: 358

Answers (2)

Jo&#227;o Haas
Jo&#227;o Haas

Reputation: 2132

The current code is trying to index a variable of type Mutex<Vec<f64>>, which is not valid. The way you access the underlying data in a mutex is by calling .lock() on it, which will in turn return a structure that resembles Result<Vec<f64>, Error>.

So, fixing only the line would look like this:

let num_list_vec = num_list.lock().unwrap();
let median: f64 = (num_list_vec[n4] + num_list_vec[n4 - 1]) / 2;

However, since you already locked at the start of the function this will not work, since the mutex is already locked. The best way then is to do the locking + unwraping at the start of the function and use the underlying value in all places:

fn calc_med() {
    let num_list_vec = num_list.lock().unwrap();
    let n: f64 = ((num_list_vec.len()) as f64 + 1.0) / 2.0;

    if n.fract() == 0.0 {
        let n2: usize = n as usize;
    } else {
        let n3: u64 = n.round() as u64;
        let n4: usize = n3 as usize;

        let median: f64 = (num_list_vec[n4] + num_list_vec[n4 - 1]) / 2;
        println!("{}", median);
    }
}

Edit: Checking your main, I see you are also lock().unwrap()ing in sequence a lot, which is not the way Mutex should be used. Mutex is mainly used whenever you have a need for multi-threaded programming, so that different threads cannot access the same variable twice. It also incurs a performance hit, so you shouldn't really use it in single-threaded scenarios most of the time.

Unless there's a bigger picture we're missing, you should just define your Vec in main and pass it to calc_med as an argument. If the reason you did what you did was to get it as a global, there are other ways to do that in Rust without performance hits, but due to safe design of Rust these ways are not encouraged and should only be used if you know 100% what you want.

Upvotes: 2

Carson
Carson

Reputation: 3101

Your error is the num_list is not an vector, it's a mutex with an vector inside of it. To access the value inside of a mutex, you must lock it, and then unwrap the result. You do this correctly in main.

To avoid continually unlocking and locking, it is generally best practice to lock the mutex once, at the start of the function. Rust will automatically drop the lock when the reference goes out of scope. See the updated example:

fn calc_med() { // FOR THE ATTENTION OF STACKOVERFLOW
    let nums = num_list.lock().unwrap();
    let n: f64 = (nums.len() as f64 + 1.0) / 2.0;

    if n.fract() == 0.0 {
        let n2: usize = n as usize;
    } else {
        let n3: u64 = n.round() as u64;
        let n4: usize = n3 as usize;
        
        let median: f64 = (nums[n4] + nums[n4 - 1]) / 2;
        println!("{}", median);
    }
}

Upvotes: 1

Related Questions