Rust function does not have static lifetime?

2019-01-25 12:40发布

问题:

I am trying to make this simple code compile:

fn dox(x: u8) -> u8 { x*2 }

fn main() {
    let cb: &'static (Fn(u8) -> u8) = &dox;
}

But it fails with Rust 1.9:

x.rs:4:40: 4:43 error: borrowed value does not live long enough
x.rs:4     let cb: &'static (Fn(u8) -> u8) = &dox;
                                              ^~~
note: reference must be valid for the static lifetime...
x.rs:4:44: 5:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 4:43
x.rs:4     let cb: &'static (Fn(u8) -> u8) = &dox;
x.rs:5 }
error: aborting due to previous error

How is it possible that a free function does not have static lifetime? How could this code be unsafe?

回答1:

As of Rust 1.21, "static promotion" is performed automatically and your original code compiles as-is.

This code compiles as well:

fn main() {
    let a: &'static i32 = &5;
}

Additionally, closures which do not capture anything from their environment can be automatically converted to function pointers, so you don't need to create a separate function, either:

fn main() {
    let cb: fn(u8) -> u8 = |x| x * 2;
}


回答2:

The type of &dox is not &Fn(u8) -> u8 (or even &fn(u8) -> u8), it is merely coercible to &Fn(u8) -> u8. Therefore, you're actually taking the address of a temporary. Temporaries aren't promoted to 'static lifetime even if they could, in principle, be 'static. For example this code doesn't work either:

fn main() {
    let a: &'static i32 = &5;
}

There are some workarounds for this. Normally one can just explicitly create a static variable and take the reference to that:

fn main() {
    static FIVE: i32 = 5;
    let a: &'static i32 = &FIVE;
}

In your specific case that doesn't work directly because Fn(u8) -> u8 is an unsized type (a trait, specifically) so you can't just put that in a static. You can do this:

fn main() {
    static DOX: fn(u8) -> u8 = dox; // note: fn, not Fn
    let a: &'static Fn(u8) -> u8 = &DOX;
}

However, a static reference to a Fn* trait object is a rather silly thing. Closures which can be 'static references are extremely rare, so you might just as well use a plain fn(u8) -> u8 type and sidestep the whole lifetime business.



标签: rust lifetime