Stuck: How do I specify a lifetime on a struct without a PhantomData?

I'm really stuck trying to work code similar to the following:-

pub struct StructWithCallback<'a, C: Fn(u16, &'a str, &'a str) -> u16>
{
    some_data: u16,
    first_name: String,
    last_name: String,
    callback: C,
}

impl<'a, C: Fn(u16, &str, &str) -> u16> StructWithCallback<'a, C>
{
    fn do_something_with_callback(&self) -> u16
    {
        (self.callback)(self.some_data, &self.first_name, &self.last_name)
    }

}

fn sample_callback<'b>(some_data: u16, first_name: &'b str, last_name: &'b str) -> u16
{
    45
}

fn main()
{
    let x = StructWithCallback
    {
        some_data: 16,
        first_name: "Hello".to_string(),
        last_name: "World".to_string(),
        callback: sample_callback,
    };
    
    x.do_something_with_callback()
}

Of course, this doesn't work; rustc complains that the lifetime 'a is unused in the fields of the struct. True. It's used to define the callback definition, C. If one completely removes 'a from this code, then the lifetimes of first_name and last_name are no longer linked. How do I tell rustc that the lifetimes are linked. I want to be able to supply both functions and closures as the value of StructWithCallback.callback

Do you really need them to be linked?

If this is your only concern, you can write it like this:

pub struct StructWithCallback<C: for<'a> Fn(u16, &'a str, &'a str) -> u16>

But if you need it tied to some specific external lifetime, then you will need to have that lifetime parameter on the struct and use PhantomData after all.

Linking the two lifetimes doesn't make sense, because the struct owns the Strings, so they are already tied to the lifetime of the struct. If you want them linked because you don't want to have them owned by the struct, you need to use &'a str or &'a String (the last only if you need them growable, and I don't assume you need that).

@skade - thank you. I tried to post a simplified example - the problem with those is they can then be solved other ways!

@cuviper
Thank you - it is the for<> syntax I needed. Did I miss that in the rust book? I don't recall having seen anything like it. I have to have them linked because otherwise rustc gets very upset, and tries to infer for<'r, 'r> (yes, 'r twice)...

You didn't miss it, but there's at least a placeholder for Advanced Lifetimes in the second edition. The nomicon describes the for<'a> syntax in the chapter Higher-Rank Trait Bounds.

1 Like