一時値のライフタイム拡張

ⓘ 参考

一時値のライフタイム拡張のための正確なルールは変更の対象になるかもしれない。ここでは現在の動作のみを説明している。

let 文内の式のための一時的なスコープは時おり let 文を包含するブロックのスコープまで拡張される。これは通常の一時的なスコープが小さすぎる時に行われ、特定の構文ルールに基づく。例えば:

let x = &mut 0;
// Usually a temporary would be dropped by now, but the temporary for `0` lives
// to the end of the block.
println!("{}", x);

ライフタイム拡張は staticconst のアイテムにも適用され、そこでは一時値がプログラムの終了まで生きるようになる。例えば:

const C: &Vec<i32> = &Vec::new();
// Usually this would be a dangling reference as the `Vec` would only
// exist inside the initializer expression of `C`, but instead the
// borrow gets lifetime-extended so it effectively has `'static` lifetime.
println!("{:?}", C);

もし借用逆参照フィールド、またはタプル添字の式が拡張された一時的なスコープを持つなら、その演算対象もそうなる。もし添字式が拡張された一時的なスコープを持つなら、添字の適用対象の式もまた拡張された一時的なスコープを持つ。

パターンに基づく拡張

拡張パターンは以下のどれかである:

つまり ref xV(ref x) そして [ref x, y] は全て拡張パターンだが、x& ref x そして &(ref x,) はそうではない。

もしも let 文内のパターンが拡張パターンなら、初期化子の式の一時的なスコープは拡張される。

// This is an extending pattern, so the temporary scope is extended.
let ref x = *&temp(); // OK
// This is neither an extending pattern nor an extending expression,
// so the temporary is dropped at the semicolon.
let &ref x = *&&temp(); // ERROR
// This is not an extending pattern but it is an extending expression,
// so the temporary lives beyond the `let` statement.
let &ref x = &*&temp(); // OK

式に基づく拡張

初期化子を伴う let 文では、拡張式は以下のうちのどれか一つの式である:

つまり &mut 0(&1, &mut 2)、そして Some(&mut 3) 内の借用式は全て拡張式だが、&0 + &1f(&mut 0) 内の借用はそうではない。

任意の拡張される借用式の演算対象はその拡張された一時的なスコープを持つ。

ⓘ 参考

rustc は拡張される配列反復対象を拡張式として扱わない。そうすべきかどうかは未解決の問題である。

詳しくは、Rust issue #146092 を参照。

ここでは式が一時的なスコープを持つ例をいくつか示す:

let x = &temp(); // Operand of borrow.
let x = &raw const *&temp(); // Operand of raw borrow.
let x = &temp() as &dyn Send; // Operand of cast.
let x = (&*&temp(),); // Operand of tuple constructor.
let x = { [Some(&temp())] }; // Final expr of block.
let x = const { &temp() }; // Final expr of `const` block.
let x = unsafe { &temp() }; // Final expr of `unsafe` block.
let x = if true { &temp() } else { &temp() };
//              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//           Final exprs of `if`/`else` blocks.
let x = match () { _ => &temp() }; // `match` arm expression.
//
// All of the temporaries above are still live here.

ここでは式が一時的なスコープを持たない例をいくつか示す:

// Arguments to function calls are not extending expressions. The
// temporary is dropped at the semicolon.
let x = core::convert::identity(&temp()); // ERROR
// Receivers of method calls are not extending expressions.
let x = (&temp()).use_temp(); // ERROR
// Scrutinees of match expressions are not extending expressions.
let x = match &temp() { x => x }; // ERROR
// Final expressions of `async` blocks are not extending expressions.
let x = async { &temp() }; // ERROR
// Final expressions of closures are not extending expressions.
let x = || &temp(); // ERROR
// Operands of loop breaks are not extending expressions.
let x = loop { break &temp() }; // ERROR
// Operands of breaks to labels are not extending expressions.
let x = 'a: { break 'a &temp() }; // ERROR