Как новичок в Rust, я понимаю, что явные времена жизни служат двум целям.
Размещение явной аннотации времени жизни для функции ограничивает тип кода, который может появляться внутри этой функции. Явные времена жизни позволяют компилятору гарантировать, что ваша программа делает то, что вы хотели.
Если вы (компилятор) хотите (и) проверить, является ли фрагмент кода допустимым, вам (компилятору) не придется итеративно заглядывать внутрь каждой вызываемой функции. Достаточно взглянуть на аннотации функций, которые напрямую вызываются этим фрагментом кода. Это делает вашу программу намного проще для вас (компилятор) и делает время компиляции управляемым.
В пункте 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
), компилятор жалуется на несоответствие времени жизни. В нужном месте. В нужное время. Отладка на одном дыхании.