简体   繁体   中英

How to make Fn(T) + 'static register as 'static for any generic type argument T?

I'm using the specs crate which has a Component trait which extends the std::any::Any trait (the Any trait just requires 'static ). I want to include a Box<Fn(T) + 'static> field (with generic argument T ) in a struct for which Component is implemented, which means Box<Fn(T) + 'static> needs to be 'static . That means I need Fn(T) + 'static to be 'static for any T .

It seems Fn(T) + 'static is not 'static for any generic type argument T . T could refer to a struct with its own lifetimes, but I expected it not to be a problem because there is no instance of a reference with those lifetimes in the Fn to make the Fn itself not 'static - those lifetimes are only in the arguments passed to the Fn , but it is as if Fn(T) + 'static is considered to contain a T itself.

Example:

struct HandlesT<T> {
    handler: Box<Fn(T) + 'static>,
}

impl<T> HandlesT<T> {
    pub fn new<F: Fn(T) + 'static>(handler: F) -> HandlesT<T> {
        HandlesT {
            handler: Box::new(handler),
        }
    }
}

trait IsStatic: 'static {}
impl<T> IsStatic for HandlesT<T> {}
error[E0310]: the parameter type `T` may not live long enough
  --> src/lib.rs:14:9
   |
14 | impl<T> IsStatic for HandlesT<T> {}
   |      -  ^^^^^^^^
   |      |
   |      help: consider adding an explicit lifetime bound `T: 'static`...
   |
note: ...so that the type `HandlesT<T>` will meet its required lifetime bounds
  --> src/lib.rs:14:9
   |
14 | impl<T> IsStatic for HandlesT<T> {}
   |         ^^^^^^^^

In the example, since HandlesT<T> contains no non-static references at all for any given T (no references at all except those owned by the Fn , but those must be 'static ), I expected HandlesT<T> to be static for any T , but the error indicates that it is not.

The compiler suggestion to "consider adding an explicit lifetime bound T: 'static " neither supports any generic type argument T, nor provides hints as to why HandlesT<T> for any generic T is not 'static , given that HandlesT<T> would not contain a T .

Example of T: 'static (the compiler's suggestion) not supporting any generic T , in this case &'a i32 :

struct HandlesT<T: 'static> {
    handler: Box<Fn(T) + 'static>,
}

impl<T: 'static> HandlesT<T> {
    pub fn new<F: Fn(T) + 'static>(handler: F) -> HandlesT<T> {
        HandlesT {
            handler: Box::new(handler),
        }
    }
}

trait IsStatic: 'static {}
impl<T: 'static> IsStatic for HandlesT<T> {}

fn try_nonstatic_t<'a>() {
    let handles_t = HandlesT {
        handler: Box::new(|i: &'a i32| {}),
    };
}
error[E0477]: the type `&'a i32` does not fulfill the required lifetime
  --> src\lib.rs:17:21
   |
17 |     let handles_t = HandlesT {
   |                     ^^^^^^^^
   |
   = note: type must satisfy the static lifetime

A discussion on discord about this yielded Issue 57325 and the discussion there seems to have left things in a state of:

  • It's not logically correct ("language wart")
  • Backwards compatibility may make fixing it impossible
  • Would probably require an RFC to fix, it was closed as "working as expected for now"
  • See RFC 1214 for justification of why it is implemented the way it is today.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM