Я изучаю концепцию продолжительности жизни из Книги по коричневой ржавчине.
И я сначала подумал, что компилятору нужно время жизни, потому что он не может сказать время жизни ссылок без него, поэтому нам, программистам, нужно это сообщить.
Однако в одном примере книги приводится код, который невозможно скомпилировать. потому что компилятор обнаружил, что время жизни неверно.
Итак, мой вопрос в том, что в этом случае компилятор определенно может найти неправильное время жизни. и даже подскажите, как это исправить. Не означает ли это, что компилятор определенно знает время жизни ссылок, участвующих в этой функции. В этом смысле, почему программисты удосуживаются добавлять время жизни в сигнатуру функции?
Пример и вывод компилятора:
fn shortest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
if x.len() < y.len() {
x
} else {
y
}
}
fn main() {
println!("{}", shortest("hello", "rust"));
}
|
1 | fn shortest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
5 | y
| ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`
Мы, программисты, предоставляем пожизненные аннотации для подтверждения наших намерений, а компилятор проверяет, что наш код не нарушает эти утверждения. Когда компилятор обнаруживает нарушение, это может быть связано либо с неправильным аннотированием времени жизни, либо с неправильным кодом: компилятор не знает, что именно.
Связано: stackoverflow.com/a/67816688/5397009
Итак, мой вопрос: в этом случае компилятор определенно может обнаружить неправильное время жизни [...] Не означает ли это, что компилятор определенно знает время жизни ссылок, которые участвуют в этой функции. В этом смысле, почему программисты удосуживаются добавлять время жизни в сигнатуру функции?
Определить правильность данного решения уравнения гораздо проще, чем решить его. Другими словами, возможность компилятора проверить ваши пожизненные аннотации не означает, что он может создать их за вас.
...и даже скажи мне, как это исправить
Вот это правильный вопрос. И у него есть три ответа.
Производительность. Если компилятору придется анализировать весь ваш код, чтобы определить его время жизни, это будет намного медленнее (это своего рода противоядие от следующей причины: оно объясняет, почему компилятор не может делать это локально (т. е. анализируя одну функцию каждый раз) , это объясняет, почему он не может сделать это глобально (т.е. путем совместного анализа всех функций).
Точность. Предложения компилятора так же хороши, как и предложения, и даже там их еще можно улучшить, но они уже нигде не смогут заменить программу проверки заимствований. В этом простом примере они правы, но в более сложных фрагментах быстро запутываются. Баги заполняются почти каждый день. Когда дело доходит до диагностики, это проблемы, которые приятно улучшить качество жизни, но они нанесут вред, если компилятор будет использовать только их.
Хуже того, диагностика компилятора настолько хороша, потому что она содержит информацию, на которую вы можете положиться компилятору. Если бы компилятору пришлось делать все это самостоятельно, это было бы гораздо менее точно.
В качестве подпричины нам нравится, чтобы языковые правила были простыми, потому что так их можно легко понять. Выводы о времени жизни кросс-функций совсем не просты для понимания.
Читабельность. Rust принял явное решение провести четкую границу: внутри функции многое выводится (например, не только время жизни, но и типы). Но за пределами функций при определении границ API все должно быть явно (из этого есть несколько исключений, но большинство частей языка подчиняются этому правилу). Это помогает компилятору, но не меньше помогает и программисту. Когда вы видите функцию в Rust, вы сразу же знаете ее тип и требования к сроку службы, и это служит документацией и помогает прояснить цель.
Определить правильность данного решения уравнения гораздо проще, чем решить его. Итак, вы доказали, что P != NP? :-D
@RichardNeumann Нет, я доказал, что мы не знаем, = P = NP.
Потому что компилятор не знает, какое время жизни
x
иy
должно иметь. Если вы присвоите им разные параметры времени жизни'a
и'b
и вернете ссылку со временем жизни'a
из функции, компилятор может в этом случае сделать вывод, что'b: 'a
, поэтому он скажет вам добавить это необходимое ограничение. Однако вы также можете сообщить компилятору, что ожидаете, чтоx
иy
будут иметь одинаковое время жизни: Детская площадка