Ссылка имеет меньшее время жизни, чем ее значение из той же области?

В моем коде видно, что значение живет дольше, чем ссылка на него, хотя оба они созданы в одной области. Я хотел бы знать, почему и как я могу изменить время жизни моей ссылки.

Пример 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();

person Miles    schedule 21.04.2017    source источник


Ответы (2)


В первом примере вы перемещаете rx в rxs vec. Это нормально, потому что вы также передаете право собственности на rx, и он не будет удален.

Во втором примере вы передаете ссылку на sel.handle(), что является другим способом сказать, что он заимствован. rx удаляется в конце каждой итерации цикла, но handles переживает весь цикл. Если бы компилятор не остановил это, то handles был бы полон висящих указателей.

Но почему у ссылки время жизни отличается от значения

Ссылка всегда имеет более короткий срок жизни, чем значение, на которое она ссылается. Это должно быть так: ссылка должна существовать и быть размещена в памяти, прежде чем вы сможете найти ее адрес. После удаления значения любая ссылка на него указывает на освобожденную память, которая может использоваться для чего-то еще.

и если значение можно переместить в структуру, как в первом примере, почему бы не ссылку, как во втором?

Во втором примере ссылка перемещается. Но исходное значение - нет. Ссылка теперь указывает на свободную память, которая ранее использовалась rx.

В третьем примере вы создали векторы, которым принадлежат все Sender и Receiver. Пока txs и rxs остаются в области видимости, эти значения не удаляются.

person Peter Hall    schedule 21.04.2017
comment
поэтому, если бы я сначала создал rxs, txs, а затем построил дескрипторы как вектор ссылок в rxs, Пример 2 стал бы эквивалентным Примеру 3. - person Miles; 21.04.2017
comment
да. Но когда вы заимствуете значение из среза, вы заимствуете весь срез, что затрудняет или делает невозможным его императивную запись без unsafe кода для извлечения новых фрагментов и убеждения компилятора в том, что это нормально. Итераторы не имеют этой проблемы, потому что их конструкция заставляет каждое изменяемое заимствование завершаться до того, как произойдет следующее. Здесь есть полезная информация об этом: doc.rust-lang.org/nomicon /borrow-splitting.html - person Peter Hall; 21.04.2017

В примере 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);

Пример 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 `&`
person notriddle    schedule 21.04.2017
comment
ах, так мой & x был чрезмерным, и компилятор получил Deref'd? - person Miles; 21.04.2017