enum ManagedSlice<'a, T: 'a> {
Borrowed(&'a T),
Owned(T)
}
struct B<'a>{
m: ManagedSlice<'a, Vec<u8>>
}
impl<'a> B<'a> {
pub fn new() -> B<'a> {
let m = ManagedSlice::Owned(vec![]);
B{
m: m
}
}
}
fn main() {
let b = B::new();
}我写这段代码是为了测试我是否真的理解生命周期。当我创建let b = B::new()时,我得到一个具有特定生存期'x的B<'x>。从理论上讲,这应该是m的生命周期。但是正如您所看到的,m的生命非常短暂,只能在new中生存。
当有东西移动的时候,一生会发生什么?m是否获得B的生命周期
下面的修改如何:
enum ManagedSlice<'a, T: 'a> {
Borrowed(&'a T),
Owned(T)
}
struct B<'a>{
m: ManagedSlice<'a, Vec<u8>>
}
impl<'a> B<'a> {
pub fn new(s: &'a u8) -> B<'a> {
let m = ManagedSlice::Owned(vec![]);
B{
m: m
}
}
}
fn main() {
let b;
{
let n = 0;
b = B::new(&n);
}
}现在我强制'a拥有n的生命周期。我预计这不会被编译,因为n的生命周期很短,而b的类型是B<lifetime of n>,但是b的生命周期比n长。
这是怎么回事?
发布于 2021-05-08 17:15:36
生命周期不是变量。你不能让它们等于任何东西,或者扩展它们,或者缩短它们。他们绝对不能控制事物的寿命。
它们只是我们程序员对我们的代码所做的断言(或者,如果你愿意,可以称之为“声明”):
fn new(s: &'a u8) -> B<'a>在这里,您断言,对于每个对new的调用,都有一个生命周期'a,将为其借用s,并通过该生命周期将返回的B参数化。到目前为止,还没什么用。
现在,有趣的是:
b = B::new(&n);Rust知道您对B::new所做的断言,这里有一个对B::new-so的调用,它验证此调用的断言是否成立……
在这种情况下,'a的生命周期是多少?编译器知道函数参数s (在本例中是实参&n )是为'a借用的;这限制了'a的生命周期不能长于借用&n的生命周期,该生命周期必须在n在其代码块末尾超出作用域时被删除之前明确结束-但我们随后会尝试将函数的结果赋给b,它存在的生命周期更长。这违反了我们关于函数返回值的生命周期的断言,Rust通过编译失败让我们知道了这一点。
最后,我们只讨论与借用相关的生命周期:当某个东西被拥有时,只要它存在,它就会一直存在(实际上,请注意您对ManagedSlice的定义并没有在Owned变体中使用它的生命周期参数);当m被移到新实例化的B中时,它的生命周期就是该B的生命周期。此外,因为m是一个ManagedSlice::Owned,所以对'a的唯一约束是T: 'a,在我们的例子中,T是Vec<u8>:这意味着'a不能超过Vec<u8>引用的任何内容(例如它的底层堆分配)-effectively我们断言的是显而易见的一点是,Vec必须至少与拥有它的<'a>D30一样长(但Rust无论如何都需要这样做,即使没有显式提供断言)。
发布于 2021-05-08 14:27:48
当有东西移动的时候,一生会发生什么?移动表示从一个内存位置到另一个内存位置的数据传输,而不是对内存位置的引用,该内存位置将具有与其相关联的生命周期。因此,移动的值的生命周期与保存该值的变量在作用域中的时间一样长,而移动它将导致新值的生命周期为保存该值的新变量在作用域中的时间。
至于你的第二个例子,如果你在内部代码块之外添加一个对b的引用,那么你会得到你期望的编译器错误。编译器足够聪明,知道即使b定义在上面的作用域中,它也不会在内部作用域之外使用,因此b的生命周期等于&n的生命周期
https://stackoverflow.com/questions/67444620
复制相似问题