简体   繁体   中英

Lifetime bounds of not owned generic arguments

use std::marker::PhantomData;

struct S<'a, A> {
    _phantom: PhantomData<*const A>,
    value: &'a i32,
}

fn foo<'a, A>(value: &'a i32) {
    let s: &'a S<'a, A> = &S {
        _phantom: PhantomData,
        value,
    };
}

fn main() {}

Struct S actually don't owns generic argument A , so lifetime of A don't relate to lifetime of S . However Rust compiler output error in let s: &'a S<'a, A> :

the parameter type `A` may not live long enough
...so that the reference type `&'a S<'a, A>` does not outlive the data it points at
    consider adding an explicit lifetime bound...: `A: 'a`

Why is lifetime of A bounded? Can we get independent A from the lifetime of S ?

(Edit) The above code has another problem about reference to S in foo . More healthy code is:

use std::marker::PhantomData;

struct S<'a, A> where Self: 'a {
    _phantom: PhantomData<*const A>,
    value: &'a i32,
}

fn foo<'a, A>(value: &'a i32) {
    let s: S<'a, A> = S {
        _phantom: PhantomData,
        value,
    };
}

fn main() {}

[in let s: &'a S<'a, A> ] Why is lifetime of A bounded [to 'a ]?

When you write &'x T it implies T: 'x and is read as Any type [including reference types] that T contain must be valid during 'x .

In &'a S<'a, A> that basically means:

  • S<'a, A>: 'a which means:
    • &'a i32: 'a => 'a: 'a
    • PhantomData<*const A>: 'a => *const A: 'a => A: 'a .

But when looking at our environment (the fn signature fn foo<'a, A>(value: &'a i32) ) the A: 'a is not true hence the error.

Can we get independent A from the lifetime of S ?

[ Inside of fn foo I suppose? ] You can remove 'a lifetime from the reference: let s: &S<'a, A> to get build passing. In this case compiler will use a special unnamed lifetime 'free_region :

let s: &'free_region S<'a, A>

where 'free_region is any lifetime in which S<'a, A> is valid ie S<'a, A>: 'free_region which means 'a: 'free_region and A: 'free_region

For better understanding here is another example

Consider adding a second input lifetime 'region :

fn foo<'a, 'region, A>() {
    let s: &'region S<'a, A>;
}

We see that both of lifetimes and A are unrelated to each other. And rustc gives us a reasonable error:

error[E0491]: in type `&'region S<'a, A>`, reference has a longer lifetime than the data it references
 --> src/main.rs:9:12
  |
9 |     let s: &'region S<'a, A>;
  |            ^^^^^^^^^^^^^^^^^
  |
note: the pointer is valid for the lifetime `'region` as defined on the function body at 8:12
 --> src/main.rs:8:12
  |
8 | fn foo<'a, 'region, A>(value: &'a i32) {
  |            ^^^^^^^
note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 8:8
 --> src/main.rs:8:8
  |
8 | fn foo<'a, 'region, A>(value: &'a i32) {
  |        ^^

We must provide 'a: 'region and A: 'region bounds either in where clauses:

fn foo<'a, 'region, A>()
where
    'a: 'region,
    A: 'region,
    // or just simply
    S<'a, A>: 'region,
{
    let s: &'region S<'a, A>;
}
    

or via RFC 2093: Infer T: 'x outlives requirements on structs

fn foo<'a, 'region, A>(
    _: &'region &'a i32,
    _: &'region PhantomData<*const A>,
    // or just simply
    _: &'region S<'a, A>,
) {
    let s: &'region S<'a, A>;
}

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