2

I'd like to move a MutexGuard around. Returning a MutexGuard from a function works fine without giving a lifetime parameter. But when packing the guard into a struct, the compiler demands a lifetime parameter for the guard.

The following code compiles without errors:

struct Queue {
    queue: Mutex<Vec<i32>>,
}

impl Queue {
    pub fn get_mutex_guard(&self) -> MutexGuard<Vec<i32>> {
        self.queue.lock().unwrap()
    }
}

When I try to pack the MutexGuard into a struct:

struct QueueHandle {
    handle: MutexGuard<Vec<i32>>,
}

the compiler complains about a missing lifetime parameter:

error[E0106]: missing lifetime specifier
 --> mutex-guard.rs:8:13
  |
8 |     handle: MutexGuard<Vec<i32>>
  |             ^^^^^^^^^^^^^^^^^^^^ expected lifetime parameter

To my understanding, the requirements for lifetime parameters should be the same for function return types and structs. What am I missing here?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Sascha
  • 429
  • 2
  • 6
  • I know, that there a better suited types for queues, but Vec does the job for experimenting. – Sascha Jun 20 '18 at 19:07
  • 1
    I believe your question is answered by the answers of [What is lifetime elision in very simple terms?](https://stackoverflow.com/q/40325690/155423) and [Why can the lifetimes not be elided in a struct definition?](https://stackoverflow.com/q/27785671/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jun 20 '18 at 19:40
  • @Shepmaster, I think there are two things to realize, to answer this question. First, like you have pointed out in your comment, the fact that lifetime elision exists (I wasn't aware of this) and it exists only for function declarations. This explains the different situation between declaring the function and declaring the struct. Second, one needs to realize, that the MutexGuard struct declaration actually takes a lifetime parameter, because it holds a reference. That's very easy to overlook if one isn't used to work with lifetime parameters. – Sascha Jun 24 '18 at 19:30
  • *That's very easy to overlook if one isn't used to work with lifetime parameters* — A future version of Rust will improve that. The function signature will need to be `pub fn get_mutex_guard(&self) -> MutexGuard<'_, Vec>`, indicating that lifetimes are in play. – Shepmaster Jun 24 '18 at 19:47

1 Answers1

1

This is more or less arbitrary design decision in Rust.

In functions there's lifetime elision, where the compiler guesses what lifetime the struct could have based on lifetimes of references in function arguments.

When you have foo(&'a self) -> Struct<'a> there's only one lifetime possible (apart from 'static). This is such a common case that Rust allows this to be implied for convenience: foo(&self) -> Struct.

Definition of references in structs wasn't deemed to be common and unambiguous enough to also have elided lifetimes, and the desire to have explicit lifetime definitions won.

Kornel
  • 97,764
  • 37
  • 219
  • 309