Interior mutability - cannot return value referencing temporary value

Hi,

For fun, I implemented a queue with two stacks. The queue's peek method should take &self , instead of &mut self as the mutation is not observable from the outside. However, when using RefCell's, I get error
message

cannot return value referencing temporary value

which I understand, but don;t know a way around. Does anybody know how to do this? Code here.

Thank you,

You need to either return Ref or return a smart pointer that wraps Ref. You can't return a normal reference.

1 Like

Note that in your &mut self methods, you should prefer to use RefCell::get_mut instead of borrow or borrow_mut as get_mut is guaranteed to succeed. To solve the returning reference issue, you can return a Ref instead.

fn peek(&self) -> Option<Ref<u64>> {
    if self.dequeue_stack.borrow().is_empty() {
        let mut deque_ref = self.dequeue_stack.borrow_mut();
        let mut enque_ref = self.enqueue_stack.borrow_mut();
        while !enque_ref.is_empty() {
            let item = enque_ref.pop();
            deque_ref.push(item);
        }
        if deque_ref.is_empty() {
            return None;
        }
    }
    Some(Ref::map(self.dequeue_stack.borrow(), |stack| stack.peek().unwrap()))
}

playground

Note that the existence of this Ref will cause a panic if borrow_mut is called on dequeue_stack before the Ref is dropped. Thus the code above is designed to only call borrow_mut if items need to be moved over, which means that if a Ref still exists, the Queue is borrowed immutably, so you cannot call the &mut self methods that modify it, meaning that the api above is panic-free.

3 Likes

Thank you both for your replies.
I was hoping I can avoid Ref is the method signature as that would leak
implementation details.

You can't avoid it with RefCell, sorry.

You can wrap the Ref in your own type, but you can't get rid of it.

OK, thank you both very much. Good to know...