一時値のライフタイム拡張
ⓘ 参考
一時値のライフタイム拡張のための正確なルールは変更の対象になるかもしれない。ここでは現在の動作のみを説明している。
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);ライフタイム拡張は
staticとconstのアイテムにも適用され、そこでは一時値がプログラムの終了まで生きるようになる。例えば: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);もし借用、逆参照、フィールド、またはタプル添字の式が拡張された一時的なスコープを持つなら、その演算対象もそうなる。もし添字式が拡張された一時的なスコープを持つなら、添字の適用対象の式もまた拡張された一時的なスコープを持つ。
パターンに基づく拡張
拡張パターンは以下のどれかである:
参照や可変参照により束縛される識別子パターン。
let ref x = temp(); // Binds by reference. let ref mut x = temp(); // Binds by mutable reference.構造体、タプル、タプル構造体、スライス、または直下のサブパターンの最低でもどれか一つが拡張パターンとなる選択パターン。
struct W<T>(T); let W { 0: ref x } = W(()); // Struct pattern. let W(ref x) = W(()); // Tuple struct pattern. let (W(ref x),) = (W(()),); // Tuple pattern. let [W(ref x), ..] = [W(())]; // Slice pattern. let (Ok(W(ref x)) | Err(&ref x)) = Ok(W(())); // Or pattern. // // All of the temporaries above are still live here.つまり
ref x、V(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 文では、拡張式は以下のうちのどれか一つの式である:
- 初期化式。
- 拡張される借用式の演算対象。
- 拡張される配列、キャスト、中括弧つき構造体、またはタプル式。
- 拡張されるタプル構造体またはタプル変異形のコンストラクタ式への引数。
- 拡張されるブロック式の最後の式、ただし非同期ブロック式は除く。
- 拡張される
if式のブロック (先頭、else if、そしてelse) の最後の式。- 拡張される
match式のアーム式。つまり
&mut 0、(&1, &mut 2)、そしてSome(&mut 3)内の借用式は全て拡張式だが、&0 + &1とf(&mut 0)内の借用はそうではない。任意の拡張される借用式の演算対象はその拡張された一時的なスコープを持つ。
例
ここでは式が一時的なスコープを持つ例をいくつか示す:
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