0

I tried to simplify my program, but there is no error if I use a simple HashMap<u16, u16> instead of my nested HashMap Polynome class.

You will need these imports to reproduce the problem:

use std::collections::{HashMap, BTreeMap};
use std::hash::{Hash, Hasher};

These are my types:

pub struct VarIdx(pub BTreeMap<u16, u8>);
pub type Polynome = HashMap<VarIdx, f64>;

This is stuff I need to make the nested HashMap work:

impl PartialEq for VarIdx {
    fn eq(&self, other: &VarIdx) -> bool {
        if self.0 == other.0 {
            return true;
        }
        if self.0.len() != other.0.len() {
            return false;
        }
        for (k, v) in self.0.iter() {
            match other.0.get(k) {
                Some(v1) => {
                    if v != v1 {
                        return false;
                    }
                }
                None => {}
            }

        }
        (true)
    }
}
impl Eq for VarIdx {}
impl VarIdx {
    pub fn len(&self) -> usize {
        return self.0.len();
    }
}
impl Hash for VarIdx {
    fn hash<H>(&self, _state: &mut H)
    where
        H: Hasher,
    {
        for (k, v) in self.0.iter() {
            k.hash(_state);
            v.hash(_state);
        }
    }
}

I have this function to find the first reasonable key:

fn get_first_product(poly: &Polynome) -> Option<&VarIdx> {
    for (key, coeff) in poly {
        if key.len() < 2 {
            return None;
        }
        return Some(key);
    }
    None
}

I want to invoke this function and perform some manipulation based on returned key, for simplicity I want to remove this key from the HashMap:

fn reduce_product(poly: &mut Polynome) -> bool {
    let key = {
        let res = get_first_product(poly);
        if res == None {
            return false;
        }
        res.unwrap()
    };
    poly.remove(&key);
    true
}

This doesn't compile, because poly is borrowed to get_first_product and can't be reborrowed:

error[E0502]: cannot borrow `*poly` as mutable because it is also borrowed as immutable
  --> src/main.rs:64:5
   |
60 |         let res = get_first_product(poly);
   |                                     ---- immutable borrow occurs here
...
64 |     poly.remove(&key);
   |     ^^^^ mutable borrow occurs here
65 |     true
66 | }
   | - immutable borrow ends here

How can I solve this elementary task? I tried to .clone() before passing poly to get_first_product(), but I get another error message:

error[E0599]: no method named `clone` found for type `&mut std::collections::HashMap<VarIdx, f64>` in the current scope
  --> src/main.rs:65:42
   |
65 |         let res = get_first_product(poly.clone());
   |                                          ^^^^^
   |
   = note: the method `clone` exists but the following trait bounds were not satisfied:
           `VarIdx : std::clone::Clone`

I have .clone() implemented for VarIdx.

What is recommended way to handle such case? I would like to avoid .clone to have an efficient program.

This doesn't seem to be duplicate of this question, because if I try to use non-nested HashMap instead of Polynome, the code compiles fine:

fn get_first_product_nonnested(poly: &HashMap<u16, u16>) -> Option<u16> {
    for (key, coeff) in poly {
        if coeff>&2 {
            return None;
        }
        return Some(*key);
    }
    None
}
fn reduce_product_nonnested(poly: &mut HashMap<u16,u16>) -> bool {
    let key = {
        let res = get_first_product_nonnested(poly);
        if res == None { return false; }
        res.unwrap()
    };
    poly.remove(&key);
    true
}

So there is something, which makes my Polynome type different from HashMap.

Stepan Yakovenko
  • 8,670
  • 28
  • 113
  • 206
  • 1
    *the first reasonable key* — [`HashMap`s have no useful ordering](https://stackoverflow.com/q/45194220/155423), so iterating over one to get the "first" anything is fairly suspicious. – Shepmaster Aug 16 '17 at 15:24
  • I have to say `rustc`'s error message "```the trait bound `&std::collections::HashMap: std::iter::IntoIterator` is not satisfied```" is totally useless, and the suggestions does not mention `VarIdx: Eq + Hash` at all. XD – kennytm Aug 16 '17 at 15:26
  • @kennytm I know that you know how to improve the compiler, so I'll watch for your PR ^_^. I assume it's difficult because you have to traverse trait implementations and see what **all** the transitive dependencies are. That being said, OP has posted what error they are getting and it's different from the error their code provides. Chances are good once their code has the matching error, it will be a duplicate. – Shepmaster Aug 16 '17 at 15:31
  • 1
    @Shepmaster I don't touch the type-checker deeply, so I'll just file an issue :p. More importantly, OP should mention what exactly the manipulation is performed, e.g. removing the key can be done with `retain`, but if the manipulation is something else the answer would be incorrect. – kennytm Aug 16 '17 at 15:37
  • 'not satisfied' message was reasonable, my inital question was missing code, required to create nested hashmap. Dear participants, please review updated version. Thanx. – Stepan Yakovenko Aug 16 '17 at 15:44
  • In my case I need any key longer then 2 entries. – Stepan Yakovenko Aug 16 '17 at 15:44
  • *non-nested `HashMap` instead of `Polynome`* — It's not a `HashMap` that makes the difference; it's that you are returning a reference (`Option<&VarIdx>`) in the code that doesn't work. In the code that works, you are *not* returning a reference, but a value instead (`Option`). If you return a `Option<&u16>`, you see the same problem. This is also a potential fix: if you can return a `Option` instead. – Shepmaster Aug 16 '17 at 17:10
  • Dear Shepmaster, please post your last comment as an answer, so I can accept it. – Stepan Yakovenko Aug 16 '17 at 17:34
  • @StepanYakovenko Since Shepmaster [closed](https://stackoverflow.com/help/closed-questions) the post as duplicate, no one can answer it here. – kennytm Aug 16 '17 at 18:36
  • Oh, I believe it was not correctly closed, Option<&VarIdx> is the rootcause of the problem. – Stepan Yakovenko Aug 16 '17 at 18:51

0 Answers0