Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying lifetimes in function pointer types in a struct

I have a function foo defined as follows:

fn foo<'a>(a: &'a i32, b: &i32) -> &'a i32 { a }

I want to store a pointer to that function in a struct:

struct S {
    f: fn(a: &i32, b: &i32) -> &i32,
}

Because there are two input lifetimes, the result lifetime cannot be inferred:

error[E0106]: missing lifetime specifier
  |
2 |     f: fn(a: &i32, b: &i32) -> &i32,
  |                                ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value,
    but the signature does not say whether it is borrowed from a or b

When I ask the compiler for foo's type, it's not very helpful either:

let () = foo;

gives me

expected type `fn(&'a i32, &i32) -> &'a i32 {foo}`

which obviously doesn't work because 'a is not defined anywhere.

So how do I declare a lifetime in this context? Trying one of

f: fn<'a>(a: &'a i32, b: &i32) -> &'a i32
f<'a>: fn(a: &'a i32, b: &i32) -> &'a i32

results in a syntax error, and I could not find documentation covering this specific situation.

like image 684
Fabian Knorr Avatar asked Dec 31 '16 14:12

Fabian Knorr


1 Answers

Define the lifetimes on the struct:

fn foo<'a>(a: &'a i32, b: &i32) -> &'a i32 { a }

struct S<'b, 'c> {
    f: fn(a: &'b i32, b: &'c i32) -> &'b i32,
}

fn main() {
    S {
        f: foo,
    };
}

Note that you cannot elide the second lifetime in this context.

But that would mean that a call to (s.f)(&x, &y) would not be generic over the lifetimes of a and b anymore, unlike foo(&x, &y)

Then you want higher-rank trait bounds (HRTBs):

fn foo<'a>(a: &'a i32, _b: &i32) -> &'a i32 { a }

struct S<F>
    where for <'b, 'c> F: Fn(&'b i32, &'c i32) -> &'b i32,
{
    f: F,
}

fn main() {
    S {
        f: foo,
    };
}
like image 180
Shepmaster Avatar answered Oct 10 '22 23:10

Shepmaster