首先,让我们谈谈lifetime elision个.所有引用都有一段与之相关的生存期,但Rust允许您在可以适当推断的情况下省略注释.
如果你要写:
fn bar_mut(x: &mut [&i32]) {
for _ in foo_mut(x) {}
}
编译器会推断每个引用都有自己的生命周期:
fn bar_mut<'a, 'b>(x: &'a mut [&'b i32]) {
for _ in foo_mut(x) {}
}
正如您所看到的,bar_mut
的签名不同于foo_mut
的签名;片&[_]
的生命周期不必与其元素&i32
的生命周期匹配,因此它不能满足foo_mut
设置的约束.
那么,为什么它对foo
和bar
都有效呢?
第二,让我们谈谈variance个.特别是,生命周期可以由编译器调整(根据它们的变化),通常调整到需要它们的最小帧.通常,引用的生存期称为covariant,这意味着编译器可以根据需要缩短它们.
如果我们看一下有明确生命周期 的bar
个:
fn bar<'a, 'b>(x: &'a [&'b i32]) {
for _ in foo(x) {}
}
当超过x
到foo
时,'b
的生命周期 缩短到与'a
匹配,它可以做到这一点,因为'b
是协变的.由于嵌套引用的构造,还有一个隐含的'b: 'a
约束,这保证了它是有效的,但目前这并不重要.
然而,mutable个引用稍微严格一些,因为它们的内容可以重新分配.可变引用的生存期仍然是协变的,但其类型references必须是invariant.否则,您将能够通过该引用分配一个生命周期短于其实际需要的值.所以,如果我们看一下你foo_mut
英镑的签名:
fn foo_mut<'a>(x: &'a mut [&'a i32]) -> ...
与片段&mut [_]
相关联的生命周期 可以是协变的,但是元素&i32
、must的生命周期 是不变的,因为它在可变引用之后.因此,'a
是不变的.因此,当我们观察bar_mut
个不同生命周期 的人时:
fn bar_mut<'a, 'b>(x: &'a mut [&'b i32]) {
for _ in foo_mut(x) {}
}
生命周期 'b
同样是不变的,因此当它通过到foo_mut
时保持不变.由于foo_mut
要求生命周期 相同,因此'a
必须与'b
匹配.而'b
不能被缩短,所以'a
必须是extended,但这是不允许的,因为'a
只是covariant(即它只能被缩短).以下是获取错误的方法:
error: lifetime may not live long enough
--> src/lib.rs:15:14
|
14 | fn bar_mut<'a, 'b>(x: &'a mut [&'b i32]) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
15 | for _ in foo_mut(x) {}
| ^^^^^^^^^^ argument requires that `'a` must outlive `'b`
我真的希望能够在不指定生存期的情况下将其定义为函数.
你之所以陷入困境,只是因为foo
和foo_mut
不必要地被过度约束了.如果您只将生命周期注释为需要的内容,则根本就没有这个问题:
fn foo<'a>(x: &'a [&i32]) -> impl Iterator<Item = ()> + 'a {
x.iter().map(|_| ())
}
fn foo_mut<'a>(x: &'a mut [&i32]) -> impl Iterator<Item = ()> + 'a {
x.iter().map(|_| ())
}
fn bar(x: &[&i32]) {
for _ in foo(x) {}
}
fn bar_mut(x: &mut [&i32]) {
for _ in foo_mut(x) {}
}
如图所示,您只需要外部生命周期,因为这是您的迭代器类型所依赖的.从技术上讲,它也依赖于&i32
的生存期,但因为嵌套引用的生存期受到内在的限制,所以您可以免费获得它.您仍然需要'a
,因为您需要告诉编译器允许您的impl Iterator
引用什么.
关键是,您应该尽可能使用不同的生存期,并且在不必要的时候省略显式.playground上的完整代码.
最后要注意的是:因为&'a mut [&'a i32]
是过度约束,所以您稍后会遇到问题using和bar_mut
.例如,您不能对相同的值调用两次.看到playground号公路上的那个故障了.参见Why does this mutable borrow live beyond its scope?,它在不同的场景中解释了更多.