Why can't I implement Deref for a specific lifetime?

Viewed 333
use std::ops::{Deref};
use std::sync::{MutexGuard};

pub struct MutexGuardRef<'a, T> {
    mutex_guard: MutexGuard<'a, Option<Box<T>>>,
}

impl<'a, T> Deref for MutexGuardRef<'a, T> {
    type Target = Option<T>;

    fn deref(&'a self) -> &'a Self::Target {
        &self.mutex_guard.deref().as_ref().map(|x|*x)
    }
}

this gives:

   = note: expected fn pointer `fn(&MutexGuardRef<'a, T>) -> &Option<T>`
              found fn pointer `fn(&'a MutexGuardRef<'a, T>) -> &'a Option<T>`

Why can't I implement a trait for a specific lifetime? Why does it have to be all lifetimes?

1 Answers

There are two issues with your code that need to be resolved.

Lifetime

Why I cannot implement a trait for a specific lifetime? Why it has to be all lifetimes?

There is no problem with implementing a trait for a specific lifetime, as in impl<'a, T> Deref for MutexGuardRef<'a, T>. In fact, that's the correct thing to do here. The compiler error arises as you implement the deref method.

I believe the confusion here results from a misunderstanding of lifetime bounds on types, such as 'a in MutexGuardRef<'a, T>. The 'a doesn't mean that every value of the type MutexGuardRef<'a, T> lives for the duration of 'a; rather, it means that type itself is bounded by 'a, which means that every value lives at most for the duration of 'a. We'll call this restriction 1.

On the other hand, when you write down &'a self, which is short for self: &'a MutexGuardRef<'a, T>, you are saying that *self, which the reference self points to, is a value that is valid for the duration of 'a; in other words, it's a value that lives at least for the duration of 'a, which we'll refer to as restriction 2.

I hope this explanation has made things clearer — restriction 1 is necessary, as it's an intrinsic property of the type; however, restriction 2 is not what we are looking for, since dereferencing a MutexGuardRef value doesn't require it to live as long as the Mutex does.

When we remove both occurrences of 'a from the implementation of deref, we get

fn deref(&self) -> &Self::Target

which is short for

fn deref(self: &MutexGuardRef<'a, T>) -> &Self::Target

Restriction 1 is preserved, whereas restriction 2 is lifted. The compiler is therefore satisfied ...

Type

... except that it greets us with another error:

error[E0308]: mismatched types
  --> src/lib.rs:12:9
   |
8  | impl<'a, T> Deref for MutexGuardRef<'a, T> {
   |          - this type parameter
...
12 |         &self.mutex_guard.deref().as_ref().map(|x|*x)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `Box`
   |
   = note: expected reference `&Option<T>`
              found reference `&Option<Box<T>>`

revealing a problem of a different kind.

&Self::Target, which stands for &Option<T>, is a reference to an Option<T> that already exists. All we have is a Mutex<Option<Box<T>>> — there is no Option<T> to point to.

Ideally, we would like deref to return an Option<&T>, which points to the innermost T wrapped in the mutex if any. However, the Deref trait dictates the return type to be of form &Self::Target, so our best call is to return &Option<Box<T>>.

The result:

use std::{ops::Deref, sync::MutexGuard};

pub struct MutexGuardRef<'a, T> {
    mutex_guard: MutexGuard<'a, Option<Box<T>>>,
}

impl<'a, T> Deref for MutexGuardRef<'a, T> {
    type Target = Option<Box<T>>;

    fn deref(&self) -> &Self::Target {
        &*self.mutex_guard
    }
}

(playground)

Related