Search code examples
rustlifetimeassociated-types

Any way to constrain lifetime of associated type?


My issue is similar to this one How do I specify an associated type with a lifetime parameter?, although slightly different.

I know, that with use of generic associated type (GATs), I can do the following

trait Displayable {
    type SomeState<'a>;

    fn show(&self, data: &mut Self::SomeState<'_>) -> String;
}

struct ThirdPartyState<'a> {
    title: &'a str,
}


struct MyMutableState<'a> {
    third: ThirdPartyState<'a>,
    buffer: Vec<u8>,
}

struct ArticleView;

impl Displayable for ArticleView {
    type SomeState<'a> = MyMutableState<'a>;

    fn show(&self, data: &mut MyMutableState<'_>) -> String {
        format!("👋 {}, {}", data.third.title, data.buffer.len())
    }
}

This works fine (playground)

However, both Displayable and ThirdPartyState<'a> are not mine, and the trait itself looks like so:

trait Displayable {
    type SomeState;

    fn show(&self, data: &mut Self::SomeState) -> String;
}

Is there any way to constrain lifetime inside this failing impl:

impl<'a> Displayable for ArticleView {
    type SomeState = MyMutableState<'a>;

    fn show(&self, data: &mut MyMutableState<'_>) -> String {
        format!("👋 {}, {}", data.third.title, data.buffer.len())
    }
}

Failing example in the playground.

Which obviously fails with:

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
  --> src/main.rs:19:6
   |
19 | impl<'a> Displayable for ArticleView {
   |      ^^ unconstrained lifetime parameter

Solution

  • I only see two options here to address this issue, even tho I would argue that none of them is ideal:

    the first one by having :

    impl Displayable for ArticleView {
        type SomeState = MyMutableState<'static>;
    
        fn show(&self, data: &mut MyMutableState<'_>) -> String {
            format!("👋 {}, {}", data.third.title, data.buffer.len())
        }
    }
    

    This fixes the error at this level, but it makes MyMutableState only working with a &'static str for ThirdPartyState.

    The second one, as first suggested by @GiM and @ChayimFriedman in their comment, required you to have a lifetime for ArticleView :

    Comment of @GiM :

    @ChayimFriedman yeah adding lifetime (and phantom data) seems to work, although that doesn't seem like a great solution :/ play.rust-lang.org/?gist=66e4d23b7439ce60243201eb3509a953

    So the result will be :

    use std::marker::PhantomData;
    struct ArticleView<'a> {
        // Note that the version of @DiM use `phantom: PhantomData<&'a u32>` which has no difference except personal preferences
        _phantom: PhantomData<&'a ()>,
    }
    
    impl<'a> Displayable for ArticleView<'a> {
        type SomeState = MyMutableState<'a>;
    
        fn show(&self, data: &mut MyMutableState<'_>) -> String {
            format!("👋 {}, {}", data.third.title, data.buffer.len())
        }
    }
    

    This unfortunately changes the way ArticleView is constructed (ArticleView { _phantom: PhantomData } instead of ArticleView)

    Otherwise, I actually don't thinks there is a way to constrains a lifetime to this impl without being able to modify the trait you want to implements