Як новачок у Расті, я розумію, що явні терміни життя служать двом цілям.
Якщо розмістити явну анотацію впродовж життя функції, обмежується тип коду, який може відображатися всередині цієї функції. Явні терміни життя дозволяють компілятору гарантувати, що ваша програма виконує те, що ви задумали.
Якщо ви (компілятор) хочете (-ла) перевірити, чи дійсний фрагмент коду, вам (компілятору) не доведеться ітеративно заглядати в кожну функцію, що викликається. Достатньо переглянути анотації функцій, які безпосередньо викликаються цим фрагментом коду. Це робить вашу програму набагато простішою міркуванням про вас (компілятора) та робить час компіляції керованим.
У пункті 1 розглянемо наступну програму, написану на Python:
import pandas as pd
import numpy as np
def second_row(ar):
return ar[0]
def work(second):
df = pd.DataFrame(data=second)
df.loc[0, 0] = 1
def main():
# .. load data ..
ar = np.array([[0, 0], [0, 0]])
# .. do some work on second row ..
second = second_row(ar)
work(second)
# .. much later ..
print(repr(ar))
if __name__=="__main__":
main()
який надрукує
array([[1, 0],
[0, 0]])
Такий тип поведінки мене завжди дивує. Що відбувається, df
це спільне використання пам'яті ar
, тому коли деякий вміст df
змін work
, які змінюються, заражаються ar
також. Однак в деяких випадках це може бути саме те, що ви хочете, з міркувань ефективності пам'яті (без копії). Справжня проблема цього коду полягає в тому, що функція second_row
повертає перший рядок замість другого; удачі налагодження цього.
Розглянемо натомість подібну програму, написану на Rust:
#[derive(Debug)]
struct Array<'a, 'b>(&'a mut [i32], &'b mut [i32]);
impl<'a, 'b> Array<'a, 'b> {
fn second_row(&mut self) -> &mut &'b mut [i32] {
&mut self.0
}
}
fn work(second: &mut [i32]) {
second[0] = 1;
}
fn main() {
// .. load data ..
let ar1 = &mut [0, 0][..];
let ar2 = &mut [0, 0][..];
let mut ar = Array(ar1, ar2);
// .. do some work on second row ..
{
let second = ar.second_row();
work(second);
}
// .. much later ..
println!("{:?}", ar);
}
Складаючи це, ви отримуєте
error[E0308]: mismatched types
--> src/main.rs:6:13
|
6 | &mut self.0
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `&mut &'b mut [i32]`
found type `&mut &'a mut [i32]`
note: the lifetime 'b as defined on the impl at 4:5...
--> src/main.rs:4:5
|
4 | impl<'a, 'b> Array<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 4:5
--> src/main.rs:4:5
|
4 | impl<'a, 'b> Array<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Насправді ви отримуєте дві помилки, є також одна з ролями 'a
та 'b
зміненими. Дивлячись на анотацію second_row
, ми виявляємо, що вихід повинен бути &mut &'b mut [i32]
, тобто вихід повинен бути посиланням на посилання на час життя 'b
(час життя другого ряду Array
). Однак, оскільки ми повертаємо перший рядок (який має все життя 'a
), компілятор скаржиться на невідповідність життя. В потрібному місці. У потрібний час. Налагодження - вітер.