Если я правильно понимаю, вопрос в том, "почему оба аргумента могут иметь одинаковое время жизни?" Короткий ответ заключается в том, что аннотации времени жизни - это не конкретные значения, а bounds - в нем говорится, что «это значение должно жить не больше / не меньше этого времени жизни».
Когда вы пишете свой код так же, как и в вопросе: fn func<'a>(s: &'a str, t: &'a str) -> &'a str
, вы буквально говорите следующее:
- есть время жизни - назовем его
'a
, которое может быть разным на каждом сайте вызова.
- аргументы
s
и t
должны оба жить не менее затем 'a
(для строковых литералов это всегда так, поскольку они 'static
, но это может не выполняться для &String
приведен к &str
) - то есть тип функции противопоказан вариант по сравнению с типами аргументов (и время жизни является частью типа).
- возвращаемое значение должно сохраняться не более затем
'a
- тип функции co вариант с возвращаемым типом.
(для получения дополнительной информации о дисперсии см. Rustonomicon )
Упрощенно, это означает, что оба аргумента должны переживать возвращаемое значение. Это не всегда то, что вы хотите - рассмотрите следующий случай (обратите внимание, что я возвращаю s
сейчас, чтобы порядок инициализации не изменился):
fn main() {
let ss = "abc";
let mut result = "";
{
let tt = "def".to_string();
result = func(ss, &tt);
}
println!("{}", result);
}
fn func<'a>(s: &'a str, t: &'a str) -> &'a str {
s
}
( детская площадка )
Этот код не будет компилироваться, хотя он логически корректен, поскольку аннотации времени жизни не согласуются с логикой: второй аргумент, t
, никак не связан с возвращаемым значением, и, тем не менее, ограничивает его время жизни. согласно аннотациям функций. Но когда мы меняем функцию на следующую:
fn func<'a, 'b>(s: &'a str, t: &'b str) -> &'a str {
s
}
... он компилирует и возвращает желаемый результат (хотя и с некоторыми предупреждениями), поскольку теперь время жизни 'b
не связано с 'a
и, фактически, может быть вообще удалено - жизненное значение elision сделает его работа хорошо.