Почему Rust не расширяет область действия этой временной переменной?

Почему Rust не расширяет область действия временного значения, на которое ссылается val3 в следующем коде:

fn main() {  
    let mut vec = vec![1, 2,3];  
  
    let val1 = vec.get(0).unwrap_or(&0);  
    println!("{val1}");  
  
    let val2 = match vec.get_mut(0) {  
        Some(v) => v,  
        None => &mut 0,  
    };  
    println!("{val2}");  
  
    let val3 = vec.get_mut(0).unwrap_or(&mut 0);
    println!("{val3}");
}

Компиляция дает следующую ошибку

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:13:46
   |
13 |     let val3 = vec.get_mut(0).unwrap_or(&mut 0);
   |                                              ^ - temporary value is freed at the end of this statement
   |                                              |
   |                                              creates a temporary value which is freed while still in use
14 |     println!("{val3}");
   |               ------ borrow later used here
   |
help: consider using a `let` binding to create a longer lived value
   |
13 ~     let binding = 0;
14 ~     let val3 = vec.get_mut(0).unwrap_or(&mut binding);
   |

For more information about this error, try `rustc --explain E0716`.
error: could not compile `question` (bin "question") due to 1 previous error

Если посмотреть на код val1, это будет работать для неизменяемой ссылки с использованием unwrap_or(). Глядя на код val2, можно увидеть, что это будет работать для изменяемой ссылки с использованием выражения соответствия. Но очевидно, что это не работает с val3 для изменяемой ссылки с использованием unwrap_or(). Кто-нибудь знает причину разницы?

Если бы мне пришлось сделать предположение, я бы сказал, что выражение match работает, потому что изменяемая ссылка на временное значение немедленно присваивается переменной в операторе let. При использовании unwrap_or() эта ссылка на временное значение вместо этого передается функции. Если ссылка является неизменяемой, она не потребляет ссылку, и назначение по-прежнему работает. Если ссылка является изменяемой, unwrap_or() потребляет ссылку, и повторное заимствование не происходит, поскольку что-то является временным значением.

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Короткий ответ: в случае val3 это не работает, потому что это не соответствует критериям временного продления жизни.

Сначала давайте разберемся со случаем val2. Это описано в этом разделе по ссылке выше:

Для оператора let с инициализатором расширяющее выражение — это выражение, которое является одним из следующих:

  • ...
  • Окончательное выражение любого выражения расширяющегося блока.

Это «окончательное утверждение» рычага спичечного блока, поэтому оно соответствует критериям. Таким образом, время жизни временного объекта увеличивается до уровня времени жизни val2.

В случае val3 он просто не соответствует критериям — в списке отсутствуют выражения вызова функций (что явно указано в следующем параграфе документации).

Так почему же это работает в случае val1? Поскольку для этого требуется общая ссылка, а не эксклюзивная, она подлежит постоянной рекламе.

Перемещение выражения значения в слот 'static происходит, когда выражение может быть записано в виде константы, заимствовано и разыменовано в том заимствовании, где выражение было изначально записано, без изменения поведения во время выполнения.

Другими словами, это фактически синтаксический сахар для:

static ZERO: i32 = 0;
let val1 = vec.get(0).unwrap_or(&ZERO);

Если вы запустили эту функцию много раз, все ссылки &0 будут указывать на одно и то же фактическое значение, которое будет переведено в хранилище статической длительности. Поскольку изменить значение через общую ссылку невозможно, проблем с этим нет.

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

Другие вопросы по теме