2017-04-21 96 views
1

它出現在我的代碼中,一個值比它的引用壽命更長,即使兩者都在相同的範圍內創建。我想知道爲什麼,以及如何調整我參考的一生。參考文獻比相同範圍的參考文獻的壽命短?

例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循環的末尾丟掉了並且需要壽命更長,大概是因爲參考是pla採用壽命更長的結構。爲什麼參考文獻的壽命會不同於這個值,如果這個值可以是移動到第一個例子中的結構中,爲什麼不能像第二個參考文獻那樣?

最後,我想知道爲什麼我不會在例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

在第一個例子要移動rxrxs VEC。這很好,因爲您也移動了rx的所有權,並且不會掉線。

在第二個示例中,您傳遞的是對sel.handle()的引用,這是另一種表示它正在借用的方式。 rx在每次循環迭代結束時被丟棄,但是handles超出整個循環。如果編譯器沒有阻止這種情況發生,那麼handles將充滿懸掛指針。

但爲什麼會參考有不同的壽命比值

的引用總是比它引用的值更短的壽命。這必須是這樣的:參考必須存在並在找到其地址之前分配給內存。值被刪除後,任何對它的引用都指向釋放的內存,這可以用於其他事情。

如果該值可以像第一個例子那樣移動到一個結構中,那麼爲什麼不能像第二個那樣引用呢?

在第二個例子中,參考被移動。但原始價值不是。現在參考文獻指出了以前由rx使用的空閒內存。

在第三個示例中,您已創建擁有所有Sender s和Receiver s的矢量。只要txsrxs保持在範圍內,這些值將不會被刪除。

+0

所以如果我已經產生RXS,TXS,然後再建手柄作爲參考的載體導入RXS,例2將成爲相當於例3 – Miles

+1

是。但是,當你從一個分片中借用一個值時,就會借用整個分片,這使得難以或不可能寫入命令性的,沒有'不安全'的代碼來提取新的分割,並說服編譯器這是好的。迭代器沒有這個問題,因爲它們的構造強迫每個可變的借位在下一個發生之前完成。有關於此的一些很好的信息在這裏:https://doc.rust-lang.org/nomicon/borrow-splitting.html –

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); 

〔實施例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 `&` 
+1

啊,所以我的&X是過度的,並得到編譯器Deref'd? – Miles