Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying `iter` chain to use `and_then`, etc

Tags:

rust

I have a function that looks like:

type Attributes = HashMap<String, json::Json>;
type Store = Arc<RwLock<HashMap<String, RwLock<Attributes>>>>;

fn get(store: &Store, key: &str) -> Option<Attributes> {
    store.read().iter()
        .filter_map(|g| (*g).get(key) )
        .filter_map(|v| v.read().ok() )
        .map(|v| (*v).clone() )
        .next()
}

This compiles and works just fine. However, for my own edification, I have been trying to modify this to use standard Result/Option methods (without converting the LockResult to an Iter), something like:

store.read().ok()
    .and_then(|g| (*g).get(key) )
    .and_then(|v| v.read().ok() )
    .map(|v| (*v).clone() );

But this tells me that g does not live long enough. I've tried adding ref and as_ref at various places, but can't get it to compile. What am I missing?

I know I can get it to work like:

    store.read().ok()
        .and_then(|g| {
            (*g).get(key)
                .and_then(|v| v.read().ok() )
                .map(|v| (*v).clone() )
        })

But I would like to be able to chain it like in the iter case.

like image 962
Jacob Brown Avatar asked Oct 18 '22 18:10

Jacob Brown


1 Answers

OK, the compiler is really messing with me tonight.

I got this incantation to compile:

fn get(store: &Store, key: &str) -> Option<Attributes> {
    let r = store.read();
    let x = r.as_ref().ok()
        .and_then(|g| (*g).get(key) )
        .and_then(|v| v.read().ok() )
        .map(|v| (*v).clone() );
    x
}

If you inline either r or x, you'll get another does not live long enough error again. I'm not sure why, since in principle, the lock guard should remain active as a temporary until the end of the statement.

like image 78
Francis Gagné Avatar answered Dec 07 '22 18:12

Francis Gagné