简体   繁体   中英

How to unpack BTreeMap item tuple from an iterator in Rust?

Here is example code:

use std::collections::BTreeMap;

fn main() {
    let mut map: BTreeMap<u8, Vec<u8>> = BTreeMap::new();
    let idx = map.iter_mut().find(|t| {
        let (&k, &mut v) = t;
        v.is_empty()
    });
    idx.map(|t| {
        let (&k, &mut v) = t;
        v.push(5);
    });
}

Errors:

<anon>:6:13: 6:25 error: mismatched types:
 expected `&(&u8, &mut collections::vec::Vec<u8>)`,
    found `(_, _)`
(expected &-ptr,
    found tuple) [E0308]
<anon>:6         let (&k, &mut v) = t;
                     ^~~~~~~~~~~~

The type of tuple is &(&u8, &mut collections::vec::Vec<u8>) so I expect it to be unpackable with following:

let (&k, &mut v) = *t;

But

<anon>:10:28: 10:30 error: type `(&u8, &mut collections::vec::Vec<u8>)` cannot be dereferenced
<anon>:10         let (&k, &mut v) = *t;
                                     ^~

How to unpack it and use for mutable purposes?

Check out the error message:

 expected `&(&u8, &mut collections::vec::Vec<u8>)`,
    found `(_, _)`
(expected &-ptr,
    found tuple) [E0308]

The compiler expects to match against a reference, but the code does not provide such. Change the binding to let &(&k, &mut v) = t . Then you get a bunch of other errors:

  1. Matching using &mut foo means that foo will have the &mut stripped off, and then the resulting value will be moved to foo . This is because it is a pattern match, just like how let Some(foo) = ... "strips off" the Some .

  2. You can't move the Vec because it's owned by the BTreeMap , so you need to take a reference to it. This is done with the ref keyword, not the & operator.

  3. Normally, you'd also do the pattern matching directly in the closure argument, not in a second variable.

  4. Since map transfers ownership of the item to the closure, you can just give that a mut binding, no need for any references.

  5. As k is unused, it's idiomatic to replace the name with an underscore ( _ ).

let idx = map.iter_mut().find(|&(k, ref v)| {
    v.is_empty()
});

idx.map(|(_, mut v)| {
    v.push(5);
});

use for mutable purposes

If you mean "how can I mutate the value in the closure to find ", the answer is "you can't". Find returns an immutable reference to the iterated item ( &Self::Item ):

fn find<P>(&mut self, predicate: P) -> Option<Self::Item> 
    where P: FnMut(&Self::Item) -> bool

Even though your Self::Item might be a mutable reference, an immutable reference to a mutable reference is still immutable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM