0

Consider this simple code:

use std::ops::Index;
use std::collections::HashMap;

enum BuildingType {
    Shop,
    House,
}

struct Street {
    buildings: HashMap<u32, BuildingType>,
}

impl Index<u32> for Street {
    type Output = BuildingType;

    fn index(&self, pos: u32) -> &Self::Output {
        &self.buildings[&pos]
    }
}

It compiles with no issues, but I cannot understand why the borrow checker is not complaining about returning a reference to temporary value in the index function.

Why is it working?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Kill KRT
  • 1,101
  • 2
  • 17
  • 37
  • What's the temporary value you see and how is it returned? – Shepmaster Oct 28 '19 at 20:52
  • `&self.buildings[&pos]` is not a temporary – Stargateur Oct 28 '19 at 20:54
  • Try saying `self.buildings[&pos]` instead, and you'll see you cannot do that. `&` in what you've written _borrows the value at_ `self.buildings[&pos]`. – Optimistic Peach Oct 28 '19 at 20:55
  • You may be interested in [What is the return type of the indexing operation?](https://stackoverflow.com/q/27879161/155423); [Is there any way to return a reference to a variable created in a function?](https://stackoverflow.com/q/32682876/155423); [Why is it legal to borrow a temporary?](https://stackoverflow.com/q/47662253/155423); [Why can I return a reference to a local literal but not a variable?](https://stackoverflow.com/q/50345139/155423) – Shepmaster Oct 28 '19 at 20:57
  • I was thinking that is a temporary value since operator [] returns a reference that is automatically deferenced by the compiler itself, so the & in front of self.building[pos] is taking a reference to a temporary value that is on the stack of the function, but maybe I have some confusion about the * works – Kill KRT Oct 29 '19 at 18:51

1 Answers1

0

You example looks fine.

The Index trait is only able to "view" what is in the object already, and it's not usable for returning arbitrary dynamically-generated data.

It's not possible in Rust to return a reference to a value created inside a function, if that value isn't stored somewhere permanently (references don't exist on their own, they always borrow some value owned somewhere).

The reference can't be borrowed from a variable inside the function, because all variables will be destroyed before the function returns. Lifetimes only describe what the program does, and can't "make" something live longer than it already does.

fn index(&self) -> &u32 {
   let tmp = 1;
   &tmp  // not valid, because tmp isn't stored anywhere
}
fn index(&self) -> &u32 {
   // ok, because the value is stored in self,
   // which existed before this function has been called
   &self.tmp 
}

You may find that returning &1 works. That's because 1 is stored in your program's executable which, as far as the program is concerned, is permanent storage. But 'static is an exception for literals and leaked memory, so it's not something you can rely on in most cases.

Kornel
  • 97,764
  • 37
  • 219
  • 309