Specifying lifetimes in fn pointer in const array

Hello,

Could you please help me set lifetimes in the BAR array?

#[derive(Default)]
pub struct Abcdef1 {
    a: String,
    b: String
}
impl Abcdef1 {
    fn abc(x: &str, y: &str) -> Abcdef1 {
        Self::default()
    }
    fn def(x: &str, y: &str) -> Abcdef1 {
        Self::default()
    }
}

#[derive(Default)]
pub struct Abcdef2<'a> {
    a: &'a str,
    b: &'a str
}
impl<'a, 'b> Abcdef2<'a> {
    fn abc(x: &'a str, y: &'b str) -> Abcdef2<'a> {
        Self::default()
    }
    fn def(x: &'a str, y: &'b str) -> Abcdef2<'a> {
        Self::default()
    }
}

pub struct Parser<'a, F> {
    name: &'a str,
    function: F
}

pub type ParsingFunction = fn(&str, &str) -> Abcdef1;
pub type ParsingFunction2<'a> = for<'b> fn(&'a str, &'b str) -> Abcdef2<'a>;

pub const FOO: [Parser<ParsingFunction>; 2] = [
    Parser { name: "hello", function: Abcdef1::abc },
    Parser { name: "hi",    function: Abcdef1::def }
];

pub const BAR: [Parser<ParsingFunction2>; 2] = [
    Parser { name: "hello", function: Abcdef2::abc }, // lifetime error
    Parser { name: "hi",    function: Abcdef2::def } // lifetime error
];

You should probably change this to

pub type ParsingFunction2 = for<'a, 'b> fn(&'a str, &'b str) -> Abcdef2<'a>;

so that the functions can parse strings with any lifetime.

1 Like

move the <'b> to the methods to support them being late-bound (i.e. the function items inherently being generic over the lifetime)

impl<'a> Abcdef2<'a> {
    fn abc<'b>(x: &'a str, y: &'b str) -> Abcdef2<'a> {
        Self::default()
    }
    fn def<'b>(x: &'a str, y: &'b str) -> Abcdef2<'a>  {
        Self::default()
    }
}
2 Likes

Eliding 'b in Abcdef2's impl block also compiles (which is syntactic sugar for what steffahn suggested).

1 Like

I'm doing something wrong...

Don't combine the suggestions :wink:

I’m still working with

pub type ParsingFunction2<'a> = for<'b> fn(&'a str, &'b str) -> Abcdef2<'a>;
1 Like

aha!, thank you!

If you want to have the for<'a, 'b> there’s no way around becoming a bit more verbose and wrapping the call into a closure. (This should have no overhead besides the additional syntax though.)

    Parser { name: "hello", function: |x, y| Abcdef2::abc(x, y) },
    Parser { name: "hi",    function: |x, y| Abcdef2::def(x, y) },

this then works with either variant of definition (the 'b can also be placed anywhere) and either variant of the fn type.

Edit: That is, unless you want to put a method on Abcdef2 that doesn’t respect the Self type fully (i.e. ignores the lifetime 'a and introduces another lifetime 'a2)

impl<'a> Abcdef2<'a> {
    fn abc<'a2, 'b>(x: &'a2 str, y: &str) -> Abcdef2<'a2> {
        Abcdef2::default() // Self::default() doesn't work anymore, either
    }
    fn def<'a2, 'b>(x: &'a2 str, y: &str) -> Abcdef2<'a2> {
        Abcdef2::default()
    }
}

Ouh, I didn't realize I can do that.

This might be the easiest option since what I really want is to put the functions into an array - I know they work, I just want to get around the type definition... Thank you.