简体   繁体   中英

What happens when a Rust struct contains a lifetimed trait?

Ok, so I'm a total Rust newbie, and I'm experimenting with Rocket. That web framework passes a Form<MyStruct> , and I want to transfer that MyStruct into my own custom struct.

struct Consumer<T> {
    d: T,
}

impl<T> Consumer<T> {
   fn new(form: Form<T>) -> Self {
       Consumer { d: form.into_inner() }
   }
}

That doesn't work of course, I get:

the trait `rocket::request::FromForm<'_>` is not implemented for `T`

Next attempt:

impl<T> Consumer<T> where T: FromForm {
    fn new(form: Form<T>) -> Self {
        Consumer { d: form.into_inner }
    }
}

Uh oh:

impl<T> Consumer<T> where T: FromForm {
                             ^^^^^^^^ expected lifetime parameter

So now I find myself completely unable to fix this! The best I can come up with is:

impl<'f, T> Consumer<T> where T: FromForm<'f> {
    fn new(form: Form<T>) -> Self {
        Consumer { d: form.into_inner }
    }
}

But that results in this error:

51 |           fn new(form: Form<T>) -> Self {                                                                                      
   |  _________^                                                                                                                    
52 | |             Consumer { d: form.into_inner }                                                                                  
53 | |         }                                                                                                                    
   | |_________^ lifetime mismatch
  = note: expected type `rocket::request::FromForm<'_>`                                                                            
             found type `rocket::request::FromForm<'f>`

Verifiable example: https://hastebin.com/eqihaqodux.makefile

Form also has a lifetime parameter. If you tie it to the lifetime of FromForm , then you'll move forward a little:

impl<'f, T> Consumer<T> where T: FromForm<'f> {
    fn new(form: Form<'f, T>) -> Self {
        Consumer(form.into_inner())
    }

    fn get(&self) -> &T {
        &self.0
    }
}

As a general rule, if you return an object that depends on data in another object, then you'll need to link their lifetimes together like this.

At this point, you'll see another error, which conveniently gives you all the information you need to fix it:

error[E0310]: the parameter type `T` may not live long enough
  --> src/main.rs:50:17
   |
48 | impl<'f, T> Consumer<T> where T: FromForm<'f> {
   |          - help: consider adding an explicit lifetime bound `T: 'static`...
49 |     fn new(form: Form<'f, T>) -> Self {
50 |         Consumer(form.into_inner())
   |                       ^^^^^^^^^^
   |
note: ...so that the type `T` will meet its required lifetime bounds
  --> src/main.rs:50:17
   |
50 |         Consumer(form.into_inner())
   |                       ^^^^^^^^^^

The into_inner method on Form requires that it's type parameter T has the 'static lifetime, and the error message suggests adding this constraint.

With these changes, it will compile:

impl<'f, T: 'static> Consumer<T> where T: FromForm<'f> {
    fn new(form: Form<'f, T>) -> Self {
        Consumer(form.into_inner())
    }

    fn get(&self) -> &T {
        &self.0
    }
}

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