Lifetime of function pointers

Hi there!

I'm currently struggling with the lifetime of function pointers. Here is my (simplified) code (link to the playground):

use std::any::Any;

#[derive(Clone, Copy)]
enum A<T: 'static> {
    VA(fn(T) -> bool)
}

enum B<T: 'static> {
    VA(Box<dyn Fn(T) -> Box<dyn Any>>)
}

impl<T: 'static> From<A<T>> for B<T> {
    fn from(a: A<T>) -> B<T> {
        match a {
            A::VA(func) => B::VA(Box::new(|val| Box::new(func(val))))
        }
    }
}

This code fails to compile with the following error :

error[E0597]: `func` does not live long enough
  --> src/lib.rs:15:58
   |
15 |             A::VA(func) => B::VA(Box::new(|val| Box::new(func(val))))
   |                                  ------------------------^^^^-------
   |                                  |        |              |
   |                                  |        |              borrowed value does not live long enough
   |                                  |        value captured here
   |                                  cast requires that `func` is borrowed for `'static`
16 |         }
17 |     }
   |     - `func` dropped here while still borrowed

error: aborting due to previous error

I don't understand why I get this error. Aren't function pointers supposed to have the 'static lifetime? I also tried to .clone() the pointer in the match arm, so I can but sure I get an fn(T) -> bool and not a reference to it, but that didn't change anything.

Any idea?

Thanks in advance for your help :slight_smile:

You can fix this with the move keyword, which makes the closure capture its arguments by value rather than reference them::

A::VA(func) => B::VA(Box::new(move |val| Box::new(func(val))))
2 Likes

Oh I see, does that mean the move keyword actually moves the values in memory?
I thought it was just a way to "transfer ownership" of a variable to another closure.

A value captured by a move closure might not necessarily change address; that's an implementation detail. The semantic meaning of move is that the closure takes ownership of the value.

(In this particular case, the value func must be moved into the new Box allocation that holds the closure, so it does in fact move to a new address in memory—assuming these allocations can't be optimized away.)

1 Like

I see. Thanks for your explanations :slight_smile:

If you want to learn more about how closures work, you can read my blog on the topic:

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.