0

Here is my original simplified code, I want to use a global variable instead of the variables in separate functions. What's the suggestion method in rust? BTW, I've tried to use global or change to function parameter, both are nightmare for a beginner. Too difficult to solve the lifetime & variable type cast issue. This simple program is only a single thread tool, so, in C language, it is not necessary the extra mutex.

// version 1
use std::collections::BTreeMap;

// Trying but failed
// let mut guess_number = BTreeMap::new();
//  | ^^^ expected item

fn read_csv() {
    let mut guess_number = BTreeMap::new();

    let lines = ["Tom,4", "John,6"];
    for line in lines.iter() {
        let split = line.split(",");
        let vec: Vec<_> = split.collect();
        println!("{} {:?}", line, vec);
        let number: u16 = vec[1].trim().parse().unwrap();
        guess_number.insert(vec[0], number);
    }
    for (k, v) in guess_number {
        println!("{} {:?}", k, v);
    }
}
fn main() {
    let mut guess_number = BTreeMap::new();
    guess_number.insert("Tom", 3);
    guess_number.insert("John", 7);
    if guess_number.contains_key("John") {
        println!("John's number={:?}", guess_number.get("John").unwrap());
    }

    read_csv();
}

To explain how hard it is for a beginner, by pass parameter

// version 2
use std::collections::BTreeMap;

fn read_csv(guess_number: BTreeMap) {
    //                    ^^^^^^^^ expected 2 generic arguments
    let lines = ["Tom,4", "John,6"];
    for line in lines.iter() {
        let split = line.split(",");
        let vec: Vec<_> = split.collect();
        println!("{} {:?}", line, vec);
        let number: u16 = vec[1].trim().parse().unwrap();
        guess_number.insert(vec[0], number);
    }
}
fn main() {
    let mut guess_number = BTreeMap::new();
    guess_number.insert("Tom", 3);
    guess_number.insert("John", 7);
    if guess_number.contains_key("John") {
        println!("John's number={:?}", guess_number.get("John").unwrap());
    }

    read_csv(guess_number);
    for (k, v) in guess_number {
        println!("{} {:?}", k, v);
    }
}

After some effort, try & error to get the possible work type BTreeMap<&str, i32>

// version 3
use std::collections::BTreeMap;
fn read_csv(guess_number: &BTreeMap<&str, i32>) {
    // let mut guess_number = BTreeMap::new();

    let lines = ["Tom,4", "John,6"];
    for line in lines.iter() {
        let split = line.split(",");
        let vec: Vec<_> = split.collect();
        println!("{} {:?}", line, vec);
        let number: i32 = vec[1].trim().parse().unwrap();
        guess_number.insert(vec[0], number);
    }
    for (k, v) in guess_number {
        println!("{} {:?}", k, v);
    }
}
fn main() {
    let mut guess_number: BTreeMap<&str, i32> = BTreeMap::new();
    guess_number.insert("Tom", 3);
    guess_number.insert("John", 7);
    if guess_number.contains_key("John") {
        println!("John's number={:?}", guess_number.get("John").unwrap());
    }

    read_csv(&guess_number);
    for (k, v) in guess_number {
        println!("{} {:?}", k, v);
    }
}

will cause following error

7  | fn read_csv(guess_number: &BTreeMap<&str, i32>) {
   |                           -------------------- help: consider changing this to be a mutable reference: `&mut BTreeMap<&str, i32>`
...
16 |         guess_number.insert(vec[0], number);
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `guess_number` is a `&` reference, so the data it refers to cannot be borrowed as mutable

The final answer (seems not suggest use global in Rust, so use 'mutable reference').

// version 4
use std::collections::BTreeMap;
fn read_csv(guess_number: &mut BTreeMap<&str, i32>) {
    let lines = ["Tom,4", "John,6"];
    for line in lines.iter() {
        let split = line.split(",");
        let vec: Vec<_> = split.collect();
        println!("{} {:?}", line, vec);
        let number: i32 = vec[1].trim().parse().unwrap();
        guess_number.insert(vec[0], number);
    }
}
fn main() {
    let mut guess_number: BTreeMap<&str, i32> = BTreeMap::new();
    guess_number.insert("Tom", 3);
    guess_number.insert("John", 7);
    if guess_number.contains_key("John") {
        println!("John's number={:?}", guess_number.get("John").unwrap());
    }

    read_csv(&mut guess_number);
    for (k, v) in guess_number {
        println!("{} {:?}", k, v);
    }
}
Daniel YC Lin
  • 15,050
  • 18
  • 63
  • 96
  • 1
    Pass the btree as parameter? – Masklinn Nov 17 '22 at 09:38
  • 2
    Does this answer your question? [How do I create a global, mutable singleton?](https://stackoverflow.com/questions/27791532/how-do-i-create-a-global-mutable-singleton) – Joe Clay Nov 17 '22 at 09:40
  • If you found a solution yourself you should add it as an answer instead of adding it to the question via an edit. – cafce25 Nov 18 '22 at 21:31

1 Answers1

1

This question is not specific to BTreeMaps but for pretty much all data types, such as numbers, strings, vectors, enums, etc.

If you want to pass a variable (value) from one function to another, you can do that in various ways in Rust. Typically you either move the value or you pass a reference to it. Moving is something quite specific to Rust and its ownership model. This is really essential, so if you have serious intentions to learn Rust, I strongly suggest you read the chapter Understanding Ownership from "the book". Don't get discouraged if you don't understand it from one reading. Spend as much time as needed, as you really can't move forward w/o this knowledge.

As for global variables, there are very few situations where they should be used. In Rust using global variables is slightly more difficult, compared to most other languages. This thread is quite useful, although you might find it a bit difficult to comprehend. My advice to a beginner would be to first fully understand the basic concept of moving and passing references.

at54321
  • 8,726
  • 26
  • 46