Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I specify the lifetime of a field as a combination of other fields?

Tags:

rust

lifetime

I have a function that stores two parameters in a struct in three referenced fields. I do not know how to specify the lifetime of this third result field, which is a combination of the lifetime of the first two parameters of the function.

I tried storing the first two reference arguments in the struct. This works quite well and is not of interest. More interesting is the case I show below, where I do not have a solution for.

I know that this code does not make any sense; it just shows the problem.

// This function can be found in "Lifetime Annotations in Function Signatures" of the Rust manual
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

// Here comes the interesting part; 1st the result type of my function
struct SillyResult<'a, 'b, 'c> {
    arg1: &'a str,
    arg2: &'b str,
    result: &'c str,
}

// ... and now the function, that does not compile and shall be corrected
fn silly_fkt<'a, 'b, 'c: 'a + 'b>(arg1: &'a str, arg2: &'b str) -> SillyResult<'a, 'b, 'c> {
    // Neither the following line ...
    // SillyResult<'a, 'b, 'c>{arg1: arg1, arg2: arg2, result: longest(arg1, arg2)}
    // ... nor the following line work
    SillyResult {
        arg1,
        arg2,
        result: longest(arg1, arg2),
    }
}

The idea was to combine lifetime 'a and 'b to a lifetime 'c. However it gives a bunch of errors complaining about the lifetimes:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to conflicting requirements
  --> src/lib.rs:25:17
   |
25 |         result: longest(arg1, arg2),
   |                 ^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime 'b as defined on the function body at 18:18...
  --> src/lib.rs:18:18
   |
18 | fn silly_fkt<'a, 'b, 'c: 'a + 'b>(arg1: &'a str, arg2: &'b str) -> SillyResult<'a, 'b, 'c> {
   |                  ^^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:25:31
   |
25 |         result: longest(arg1, arg2),
   |                               ^^^^
note: but, the lifetime must be valid for the lifetime 'c as defined on the function body at 18:22...
  --> src/lib.rs:18:22
   |
18 | fn silly_fkt<'a, 'b, 'c: 'a + 'b>(arg1: &'a str, arg2: &'b str) -> SillyResult<'a, 'b, 'c> {
   |                      ^^
   = note: ...so that the expression is assignable:
           expected SillyResult<'a, 'b, 'c>
              found SillyResult<'_, '_, '_>

I tried to change the last line of silly_fkt to

SillyResult<'a, 'b, 'c>{ arg1, arg2, result: longest(arg1, arg2) }

but this does not work.

What is the correct code for silly_fkt?

like image 240
HBex Avatar asked Mar 03 '23 18:03

HBex


1 Answers

You have the semantics of : backwards: 'c: 'a means that 'c outlives 'a, where you want to say that 'c is outlived by 'a (so that you can provide a reference of lifetime 'a where one with lifetime 'c is expected). So you need to write the lifetime constraints the other way around.

You can write <'a: 'c, 'b: 'c, 'c>, but I find it easier to read with a where clause:

fn silly_fkt<'a, 'b, 'c>(arg1: &'a str, arg2: &'b str) -> SillyResult<'a, 'b, 'c>
where
    'a: 'c,
    'b: 'c,
{
    SillyResult {
        arg1,
        arg2,
        result: longest(arg1, arg2),
    }
}
like image 84
trent Avatar answered Apr 27 '23 21:04

trent