jon
January 14, 2025, 5:03pm
1
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
];
kpreid
January 14, 2025, 5:05pm
2
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
jofas
January 14, 2025, 5:09pm
4
Eliding 'b
in Abcdef2
's impl
block also compiles (which is syntactic sugar for what steffahn suggested).
1 Like
jon
January 14, 2025, 5:10pm
5
I'm doing something wrong...
Don't combine the suggestions
I’m still working with
pub type ParsingFunction2<'a> = for<'b> fn(&'a str, &'b str) -> Abcdef2<'a>;
1 Like
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()
}
}
jon
January 14, 2025, 5:35pm
9
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.