0
votes

I'm new to rust, I've read the doc on ownership and borrowing. And obviously, I'm beginning to struggle with the concept ...

Here is my code :


#[derive(Serialize, Deserialize, Debug)]
pub struct City {
    name: String,
    dep: String,
    dynamic: String,
    population: u64, 
    cp: String,
    price_max: u8,
    price_mid: u8,
    price_min: u8,
    lng: f64,
    lat: f64,
    dist_near_city: Vec<(String, u64)>
}

fn load_cities<P: AsRef<Path>>(path: P) -> HashMap<String, City> {
    // Open the file in read-only mode with buffer.
    let file = File::open(path).expect("Unable to open file");
    let reader = BufReader::new(file);
    let retval: HashMap<String, City> = serde_json::from_reader(reader).expect("Unable to parse json");

    return retval;
}

fn update_nearby_cities(pin_city: &mut City, cities : &HashMap<String, City>, min_pop: u64, distKm: f64){
    pin_city.dist_near_city = Vec::new();
    for (id, city) in cities {
        if city.population > min_pop && is_nearby(&pin_city, &city, distKm){
            pin_city.dist_near_city.push((id.to_string(), city.population));
        }
    }
}


fn main(){
    let path  = "/home/marcel/Documents/immobilier/cities_export2.json";
    let mut cities = load_cities(path);

    for (cp, mut current_city) in &cities {
        update_nearby_cities(&mut current_city, &cities, 2000, 10.);
    }
}

I get the error for the arg &mut current_city inside the loop of the main() :

cannot borrow data in a&reference as mutable

First of all, I don't understand why I can't borrow a mutable reference because it's possible in other part of my code and in the doc (https://doc.rust-lang.org/rust-by-example/scope/borrow/mut.html)

I think it's because the loop on &cities gives me a current_city: &City and by giving &mut current_city I pass a &mut &City which is a problem (I don't know what to do with this type, I don't even think I understand what this thing is ...).

So If I try to pass only mut current_city I get Exepted expression.

The other problem I foresee, is that I'm trying to borrow the hashmap cites in the loop and reborrow it inside the loop.

How to do this kind of things properly, and is my thinking on the error are correct ?

1

1 Answers

2
votes

for entry in &cities gives a iterator over (&K, &V). If you need an iterator over (&K, &mut V) use `&mut cities'

Even with this change code will not work. You are trying to iterate & modify cities at the same time.

One easy way without doing lot of refactoring is to compute all the results at once and then add them later into the hashmap.

fn get_nearby_cities(pin_city: &City, cities : &HashMap<String, City>, min_pop: u64, distKm: f64) -> Vec<(String, u64)> {
    let mut dist_near_city = Vec::new();
    for (id, city) in cities {
        if city.population > min_pop && is_nearby(&pin_city, &city, distKm){
            dist_near_city.push((id.to_string(), city.population));
        }
    }

    dist_near_city
}


   # Compute all the required results. Unfortunately, I ended up clone the string. May be this could be avoided.
   let mut result = HashMap::new();
    for (cp, current_city) in &cities {
        result.insert(cp.clone(), get_nearby_cities(current_city, &cities, 2000, 10.));
    }

    for (city, nearby_cities) in result {
        cities.get_mut(&city).unwrap().dist_near_city.extend(nearby_cities);
    }