作为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
)的引用的引用。但是,由于我们返回的是第一行(具有lifetime 'a
),因此编译器抱怨生命周期不匹配。在正确的地方。在正确的时间。调试很容易。