Transform Option<&T> to Option<Ref<T>> or equivalent

Hello,

I'm running into an issue with interior mutability and Opntion.
Consider the following code (or playground)

use std::collections::HashMap;
use std::cell::{RefCell, Ref};

fn main() {
    let map = RefCell::new(HashMap::new());
    map.borrow_mut().insert("age", 14);
    
    fn myget(map: &RefCell<HashMap<String, String>>) -> Ref<Option<&String>> {
        Ref::map(map.borrow(), |inner| {
            &inner.get("age")
        })
    }
}

This code leads to following error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:10:20
   |
10 |             &inner.get("age")
   |                    ^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 9:32...
  --> src/main.rs:9:32
   |
9  |           Ref::map(map.borrow(), |inner| {
   |  ________________________________^
10 | |             &inner.get("age")
11 | |         })
   | |_________^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:10:14
   |
10 |             &inner.get("age")
   |              ^^^^^
note: but, the lifetime must be valid for the anonymous lifetime defined on the function body at 8:19...
  --> src/main.rs:8:19
   |
8  |     fn myget(map: &RefCell<HashMap<String, String>>) -> Ref<Option<&String>> {
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the expression is assignable
  --> src/main.rs:9:9
   |
9  | /         Ref::map(map.borrow(), |inner| {
10 | |             &inner.get("age")
11 | |         })
   | |__________^
   = note: expected `Ref<'_, Option<&String>>`
              found `Ref<'_, Option<&String>>`

Is there a way to resutnr a Option<Ref> or Ref<Option>?
Thanks for the help.

1 Like

Without the unstable filter_map, you have to do this:

use std::collections::HashMap;
use std::cell::{RefCell, Ref};

fn main() {
    let map = RefCell::new(HashMap::new());
    map.borrow_mut().insert("age", 14);
    
    fn myget(map: &RefCell<HashMap<String, String>>) -> Option<Ref<String>> {
        if map.borrow().contains_key("age") {
            Some(Ref::map(map.borrow(), |inner| {
                inner.get("age").unwrap()
            }))
        } else {
            None
        }
    }
}
2 Likes

This is a reference to a local Option<&'map String>, that is, a:

&'local Option<&'map String>

But Ref::map expects the outer reference to feature the 'map lifetime, hence the error.

More generally, you won't be able to feature Ref<'_, Option<&'_ String>> because of this, but you can swap the Ref and Option order, with a solution such as @alice's.

2 Likes

To complete this crate seems to expose a function which does exactly what I want but checking only once using unsafe code: ref_filter_map - Rust.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.