Как указать время жизни поля как комбинации других полей? - PullRequest
3 голосов
/ 08 июля 2019

У меня есть функция, которая хранит два параметра в структуре в трех ссылочных полях. Я не знаю, как указать время жизни этого третьего результирующего поля, которое является комбинацией времени жизни первых двух параметров функции.

Я попытался сохранить первые два ссылочных аргумента в структуре. Это работает довольно хорошо и не представляет интереса. Более интересным является случай, который я показываю ниже, где у меня нет решения для.

Я знаю, что этот код не имеет никакого смысла; это просто показывает проблему.

// 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),
    }
}

Идея состояла в том, чтобы объединить время жизни 'a и 'b с временем жизни 'c. Однако это дает кучу ошибок с жалобами на время жизни:

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<'_, '_, '_>

Я пытался изменить последнюю строку silly_fkt на

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

но это не работает.

Какой правильный код для silly_fkt?

1 Ответ

5 голосов
/ 08 июля 2019

У вас есть семантика : в обратном направлении: 'c: 'a означает, что 'c переживает 'a, где вы хотите сказать, что 'c пережито 'a (чтобы вы могли предоставить ссылку на время жизни 'a, где ожидается время жизни 'c). Поэтому вам нужно написать ограничения на время жизни наоборот.

Вы можете написать <'a: 'c, 'b: 'c, 'c>, но мне легче читать с предложением where:

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),
    }
}
...