Ответ 1
Позвольте мне рассказать о предыдущих ответах...
Что означает аннотация < 'a > после названия функции?
Я бы не использовал для этого слово "аннотация". Подобно <T>
вводится общий тип параметра, <'a>
вводит общий параметр времени жизни. Вы не можете использовать какие-либо общие параметры, не вводя их в первую очередь, а для общих функций это введение происходит сразу после их имени. Вы можете представить себе общую функцию как семейство функций. Таким образом, по сути, вы получаете одну функцию для каждой комбинации общих параметров. substr::<'x>
будет конкретным членом этого семейства функций для некоторого времени жизни 'x
.
Если вы неясны, когда и почему мы должны быть явными в отношении сроков жизни, читайте дальше...
Параметр lifetime всегда связан со всеми ссылочными типами. Когда вы пишете
fn main() {
let x = 1729;
let r = &r;
}
компилятор знает, что x живет в области основной функции, заключенной в фигурные скобки. Внутри он идентифицирует эту область действия с некоторым параметром времени жизни. Для нас это неназванное. Когда вы берете адрес x
, вы получите значение определенного ссылочного типа. Тип ссылки является видом члена двумерного семейства ссылочных типов. Одна ось - тип, на который ссылаются опорные точки, а другая ось - это время жизни, которое используется для двух ограничений:
- Параметр lifetime ссылочного типа представляет собой верхнюю границу того, как долго вы можете удерживать эту ссылку
- Параметр lifetime ссылочного типа представляет собой нижнюю границу для времени жизни вещей, на которые вы можете сделать контрольную точку.
Вместе эти ограничения играют жизненно важную роль в истории безопасности памяти Rust. Цель здесь - избегать оборванных ссылок. Мы хотели бы исключить ссылки, которые указывают на некоторую область памяти, которую нам больше не разрешают использовать, потому что эта вещь, к которой она обращалась, больше не существует.
Одним из потенциальных источников замешательства является, вероятно, тот факт, что параметры жизни в большинстве случаев невидимы. Но это не значит, что их там нет. В их типе всегда есть параметр продолжительности жизни. Но такой параметр lifetime не должен иметь имя и большую часть времени нам не нужно упоминать об этом, потому что компилятор может автоматически назначать имена для параметров времени жизни. Это называется "пожизненная элита". Например, в следующем случае вы не видите никаких параметров времени жизни:
fn substr(s: &str, until: u32) -> &str {…}
Но все нормально писать так. Это фактически короткий синтаксис для более явного
fn substr<'a>(s: &'a str, until: u32) -> &'a str {…}
Здесь компилятор автоматически присваивает одно и то же имя "времени жизни" и "времени жизни", потому что это очень распространенный шаблон и, скорее всего, именно то, что вы хотите. Поскольку этот шаблон настолько распространен, компилятор позволяет нам уйти, не говоря ничего о жизни. Он предполагает, что эта более явная форма - это то, что мы имели в виду на основе нескольких правил "пожизненного разрешения" (которые, по крайней мере, документированы здесь)
Существуют ситуации, когда явные параметры времени жизни не являются необязательными. Например, если вы пишете
fn min<T: Ord>(x: &T, y: &T) -> &T {
if x <= y {
x
} else {
y
}
}
компилятор будет жаловаться, потому что он будет интерпретировать вышеуказанное объявление как
fn min<'a, 'b, 'c, T: Ord>(x: &'a T, y: &'b T) -> &'c T { … }
Итак, для каждой ссылки вводится отдельный параметр времени жизни. Но никакая информация о том, как параметры жизни связаны друг с другом, доступна в этой сигнатуре. Пользователь этой универсальной функции может использовать любое время жизни. И это проблема внутри его тела. Мы пытаемся вернуть либо x
, либо y
. Но тип x
равен &'a T
. Это несовместимо с типом возврата &'c T
. То же самое верно для y
. Поскольку компилятор ничего не знает о том, как эти времена жизни относятся друг к другу, небезопасно возвращать эти ссылки в качестве ссылки типа &'c T
.
Можно ли безопасно перейти от значения типа &'a T
в &'c T
? Да. Это безопасно, если срок службы 'a
равен или больше времени жизни 'c
. Или, другими словами, 'a: 'c
. Итак, мы могли бы написать это
fn min<'a, 'b, 'c, T: Ord>(x: &'a T, y: &'b T) -> &'c T
where 'a: 'c, 'b: 'c
{ … }
и уйти с ним без компилятора, жалующегося на тело функции. Но это на самом деле излишне сложно. Мы можем просто написать
fn min<'a, T: Ord>(x: &'a T, y: &'a T) -> &'a T { … }
и используйте один параметр времени жизни для всего. Компилятор может вывести 'a
как минимальное время жизни ссылок на аргументы на сайте вызова только потому, что мы использовали одно и то же имя жизни для обоих параметров. И это время жизни именно то, что нам нужно для возвращаемого типа.
Надеюсь, это ответит на ваш вопрос.:) Ура!