在我的代码中,一个值的生命长于对它的引用,即使它们都是在同一范围内创建的。我想知道为什么,以及我如何调整参考的生命周期。
编译器接受了示例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();
答案 0 :(得分:2)
在第一个示例中,您正在将rx
移动到rxs
vec中。这很好,因为你也移动了rx
的所有权,并且它不会被放弃。
在第二个示例中,您正在传递对sel.handle()
的引用,这是另一种说法是借用它的方式。在每次循环迭代结束时删除rx
,但handles
比整个循环更长。如果编译器没有阻止这种情况发生,那么handles
就会充满悬空指针。
但为什么引用的生命周期与值
不同
引用的生命周期始终短于它引用的值。必须如此:引用必须存在并在找到其地址之前分配给内存。删除一个值后,对它的任何引用都指向释放的内存,这可能被用于其他内容。
如果值可以像第一个例子一样移动到结构中,为什么不像第二个那样引用?
在第二个示例中,引用是被移动。但原来的价值并非如此。该引用现在指向rx
之前使用的空闲内存。
在第三个示例中,您创建了拥有所有Sender
和Receiver
s的向量。只要txs
和rxs
保留在范围内,就不会删除这些值。
答案 1 :(得分:1)
在示例2中,rx
与handles
的生命周期不同。事实上,它在循环结束时被删除,如下所示:
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 `&`