Can't return value referencing temporary value return

Why RwLock create temp variable? How to resolve this ?

struct Arr<'a> {
    arr: &'a Vec<String>,
    arr2: &'a RwLock<Vec<String>>,
}
impl<'a> Arr<'a> {
    fn first(&self) -> &'a String {
        &self.arr[0]
    }
    fn second(&self) -> &'a String {
        &self.arr2.read().unwrap()[1]
    }
}

playground

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:13:9
   |
13 |         &self.arr2.read().unwrap()[1]
   |         ^-------------------------^^^
   |         ||
   |         |temporary value created here
   |         returns a value referencing data owned by the current function

The second function is simply not something you're going to be able to implement with that kind of function signature. (Even if the lifetimes are changed.). (Unless you're willing to leak an RwLockReadGuard and thus lock the RwLock forever.)

Calling read() returns a handle of type RwLockReadGuard (which is the temporary that the compiler complains about). This handle is an RAII object that manages unlocking the RwLock for you when you don't need the read access anymore. A returned &'a String cannot hide such a guard in any way.

Possible approaches (in no particular order) for changing the API are

  • return such a guard object yourself
    • either the RwLockReadGuard<'a, String> directly
      fn second(&self) -> RwLockReadGuard<'a, String>
    • or your own custom guard object wrapping this, if you don't want to expose this implementation detail
  • return an owned copy of the String
    fn second(&self) -> String
    • if you're cloning too many Strings this way, you could consider switching to something shared, cheap-to-clone like Arc<String> or Arc<str> (where Arc<String> can be more useful if you want to use the Arc in a clone-on-write manner)
      arr2: &'a RwLock<Vec<Arc<String>>>,
      fn second(&self) -> Arc<String>
  • offer a &String to a callback
    fn second<F, R>(&self, callback: F) -> R where F: FnOnce(&String) -> R

Of course if it turns out you don't need RwLock in the first place, that could help, too. Also note that using &Vec<...> or &String (i.e. shared references to vectors or strings) in Rust is considered unidiomatic; consider using &[...] and &str (i.e. slice references) instead. Consider using clippy which points out such things.

8 Likes

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.