引用的生命周期比同一范围内的值更短?

时间:2017-04-21 01:09:58

标签: loops iterator rust lifetime borrow-checker

在我的代码中,一个值的生命长于对它的引用,即使它们都是在同一范围内创建的。我想知道为什么,以及我如何调整参考的生命周期。

编译器接受了示例1 ...

let mut rxs: Vec<Receiver<String>> = Vec::new();
let mut txs: Vec<SyncSender<String>> = Vec::new();
for _ in 0..N {
    let (tx, rx) = sync_channel(0);
    txs.push(tx);
    rxs.push(rx);
}

但是示例2不是......

let sel = Select::new();
let mut handles: Vec<Handle<String>> = Vec::new();
let mut txs: Vec<SyncSender<String>> = Vec::new();
for _ in 0..N {
    let (tx, rx) = sync_channel(0);
    txs.push(tx);
    handles.push(sel.handle(&rx));
}

编译器告诉我在&rx循环的最后一行中引用for借用,但最后被删除 for循环并且需要更长寿,大概是因为引用放置在具有更长寿命的结构中。为什么引用的生命周期与值不同,如果值可以移动到第一个示例中的结构中,为什么不像第二个那样引用?

最后,我想知道为什么我在示例3中遇到相同的问题,即使引用被借用并传递到持续时间超过范围的结构中借...

let (txs, rxs): (Vec<SyncSender<String>>, Vec<Receiver<String>>) =
    (0..N).map(|_| sync_channel(0)).unzip();
let handles: Vec<Handle<String>> =
    rxs.iter().map(|x| sel.handle(&x)).collect();

2 个答案:

答案 0 :(得分:2)

在第一个示例中,您正在将rx移动到rxs vec中。这很好,因为你也移动了rx的所有权,并且它不会被放弃。

在第二个示例中,您正在传递对sel.handle()的引用,这是另一种说法是借用它的方式。在每次循环迭代结束时删除rx,但handles比整个循环更长。如果编译器没有阻止这种情况发生,那么handles就会充满悬空指针。

  

但为什么引用的生命周期与值

不同

引用的生命周期始终短于它引用的值。必须如此:引用必须存在并在找到其地址之前分配给内存。删除一个值后,对它的任何引用都指向释放的内存,这可能被用于其他内容。

  

如果值可以像第一个例子一样移动到结构中,为什么不像第二个那样引用?

在第二个示例中,引用被移动。但原来的价值并非如此。该引用现在指向rx之前使用的空闲内存。

在第三个示例中,您创建了拥有所有SenderReceiver s的向量。只要txsrxs保留在范围内,就不会删除这些值。

答案 1 :(得分:1)

在示例2中,rxhandles的生命周期不同。事实上,它在循环结束时被删除,如下所示:

let sel = Select::new();
let mut handles: Vec<Handle<String>> = Vec::new();
let mut txs: Vec<SyncSender<String>> = Vec::new();
for _ in 0..N {
    let (tx, rx) = sync_channel(0);
    txs.push(tx);
    handles.push(sel.handle(&rx));
    drop(tx);
    drop(rx);
}
drop(txs);
drop(handles);
drop(sel);

Exmaple 3与示例2不同。这相当于示例2,它失败了:

let (txs, rxs): (Vec<SyncSender<String>>, Vec<Receiver<String>>) =
    (0..N).map(|_| sync_channel(0)).unzip();
let handles: Vec<Handle<String>> =
    rxs.into_iter().map(|x| sel.handle(&x)).collect(); // <-- notice: into_iter()

iter()函数返回引用的迭代器。这就是为什么这样做的原因:

let (txs, rxs): (Vec<SyncSender<String>>, Vec<Receiver<String>>) =
    (0..N).map(|_| sync_channel(0)).unzip();
let handles: Vec<Handle<String>> =
    rxs.iter().map(|x| sel.handle(x)).collect(); // <-- notice: no `&`