The place the lifetime 'b in Ref<'b, T> comes from originally is RefCell::borrow() β it is the lifetime of a reference to the RefCell. It ensures that the Ref cannot outlive the RefCell. However, it can be arbitrarily long β even 'static β if the caller provides a suitable &'b RefCell<T>.
But the premise of a RefCell is that you can borrow the contents only as long as you have the run-time Ref or RefMut guard alive. That's how it prevents conflicts. And so any reference to the T you get must be a borrow of the Ref, not of the RefCell.
If Ref::map() had the signature proposed by @wishawa, then you could use it to break RefCell by extracting a long-lived &T:
use std::cell::{RefCell, Ref};
fn cheat<'rc, T>(cell: &'rc RefCell<T>) -> &'rc T {
let guard = cell.borrow();
let mut output = None;
Ref::map(guard, |ref_to_contents| {
output = Some(ref_to_contents);
&()
});
output.unwrap()
}
fn main() {
let cell = RefCell::new(0);
let r1: &i32 = cheat(&cell);
let r2: &mut i32 = &mut *cell.borrow_mut();
// oops, UB: r1 and r2 refer to the same memory but r2 is exclusive
}
There is, however a valid non-HRTB signature you could write:
pub fn map<'r, U: ?Sized, F>(orig: &'r Ref<'b, T>, f: F) -> Ref<'r, U>
where
F: FnOnce(&'r T) -> &'r U
{...}
Here, the f function is given a reference that is only valid as long as the Ref exists. But, in order to achieve that, it has to take a borrowed Ref, and that is less useful than the real Ref::map() β if you can keep the original Ref around to borrow it, then you can also just apply the function to the reference the guard dereferences to:
let guard = cell.borrow();
let u: &U = f(&*guard);