Là một người mới đến với Rust, sự hiểu biết của tôi là thời gian sống rõ ràng phục vụ hai mục đích.
Đặt một chú thích trọn đời rõ ràng vào một hàm sẽ hạn chế loại mã có thể xuất hiện bên trong hàm đó. Tuổi thọ rõ ràng cho phép trình biên dịch đảm bảo rằng chương trình của bạn đang làm những gì bạn dự định.
Nếu bạn (trình biên dịch) muốn (các) trình kiểm tra xem một đoạn mã có hợp lệ không, bạn (trình biên dịch) sẽ không phải lặp đi lặp lại bên trong mỗi hàm được gọi. Nó đủ để xem các chú thích của các hàm được gọi trực tiếp bởi đoạn mã đó. Điều này làm cho chương trình của bạn dễ dàng hơn nhiều để lý do cho bạn (trình biên dịch) và làm cho thời gian biên dịch có thể quản lý được.
Ở điểm 1., hãy xem xét chương trình sau được viết bằng 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()
cái nào sẽ in
array([[1, 0],
[0, 0]])
Kiểu hành vi này luôn làm tôi ngạc nhiên. Điều đang xảy ra là df
chia sẻ bộ nhớ ar
, vì vậy khi một số nội dung df
thay đổi work
, sự thay đổi đó ar
cũng bị ảnh hưởng. Tuy nhiên, trong một số trường hợp, đây có thể là chính xác những gì bạn muốn, vì lý do hiệu quả bộ nhớ (không có bản sao). Vấn đề thực sự trong mã này là hàm second_row
đang trả về hàng đầu tiên thay vì hàng thứ hai; chúc may mắn gỡ lỗi đó.
Thay vào đó hãy xem xét một chương trình tương tự được viết bằng 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);
}
Biên dịch này, bạn nhận được
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> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Trong thực tế, bạn nhận được hai lỗi, cũng có một lỗi với vai trò 'a
và 'b
thay thế cho nhau. Nhìn vào chú thích của second_row
, chúng ta thấy rằng đầu ra phải là &mut &'b mut [i32]
, nghĩa là đầu ra được coi là một tham chiếu đến một tham chiếu có thời gian tồn tại 'b
(thời gian tồn tại của hàng thứ hai Array
). Tuy nhiên, vì chúng tôi đang trả về hàng đầu tiên (có thời gian tồn tại 'a
), trình biên dịch phàn nàn về sự không phù hợp trọn đời. Đúng nơi. Vào đúng thời điểm. Gỡ lỗi là một làn gió.