一時停止は、C++の場合と同様に、文の最後にドロップされます。しかし、IIRCでは、Rustの破壊の順序は不明です(これについては後述します)。現在の実装では単純に逆の順序で値を落としているようです。
let _ = x;
とlet _b = x;
の間に大きな違いがあります。 _
はRustの識別子ではありません。ワイルドカードパターンです。このパターンは変数を検出しないため、最終値はステートメントの最後に効果的に削除されます。
一方、_b
は識別子であるため、値はその名前の変数にバインドされます。この値は、関数の終わりまで有効です。しかし、A
インスタンスはまだ一時的なので、ステートメントの最後に削除されます(C++は同じことをすると思います)。ステートメントの終わりは関数の終わりより前に来るので、A
インスタンスは最初に削除され、B
インスタンスは2番目に削除されます。
これをより明確にするために、のはmain
で別のステートメントを追加してみましょう。
fn main() {
let _ = B(&A as *const A);
println!("End of main.");
}
これは、次のような出力生成します。これまでのところは良い
Drop B.
Drop A.
End of main.
を。さあ、let _b
で試してみましょう。出力は次のとおりです。
Drop A.
End of main.
Drop B.
私たちが見ることができるように、Drop B
はEnd of main.
後に印刷されます。これは、関数の最後までB
インスタンスが生きていて、異なる破壊順序を説明していることを示しています。
それでは、私たちが代わりに生のポインタの寿命を借りポインタを取るためにB
を変更した場合に何が起こるか見てみましょう。実際には、のは、さらに一歩進み、一瞬Drop
実装を削除してみましょう:これは罰金コンパイル
struct A;
struct B<'a>(&'a A);
fn main() {
let _ = B(&A);
}
。背後では、RustはA
インスタンスとB
インスタンスの両方に同じ寿命を割り当てます(つまり、B
インスタンスへの参照を取得した場合、そのタイプは&'a B<'a>
となります)。の場合、両方とも'a
は完全に同じです。 2つの値が同じ寿命を持つ場合、必然的にそれらの一方を他方よりも先に落とす必要があり、上述のように、順序は不特定である。 Drop
の実装を追加するとどうなりますか? A
インスタンスとB
インスタンスの両方が同じ寿命が割り当てられているので
error: borrowed value does not live long enough
--> <anon>:8:16
|
8 | let _ = B(&A);
| ^does not live long enough
|
note: reference must be valid for the destruction scope surrounding statement at 8:4...
--> <anon>:8:5
|
8 | let _ = B(&A);
| ^^^^^^^^^^^^^^
note: ...but borrowed value is only valid for the statement at 8:4
--> <anon>:8:5
|
8 | let _ = B(&A);
| ^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> <anon>:8:5
|
8 | let _ = B(&A);
| ^^^^^^^^^^^^^^
、錆がこれらのオブジェクトの破壊の順序について推論することはできません。
struct A;
impl Drop for A { fn drop(&mut self) { println!("Drop A.") } }
struct B<'a>(&'a A);
impl<'a> Drop for B<'a> { fn drop(&mut self) { println!("Drop B.") } }
fn main() {
let _ = B(&A);
}
は、今、私たちは、コンパイラエラーを取得しています。このエラーは、B<'a>
がDrop
(このルールはRust 1.0より前にRFC 769の結果として追加されています)を実装したときに、Rustがオブジェクト自体の有効期間でB<'a>
をインスタンス化することを拒否したことに起因します。許可されている場合は、drop
はすでに削除された値にアクセスできます。ただし、B<'a>
にDrop
が実装されていない場合は、構造体が破棄されるときにコードがB
のフィールドにアクセスしようとしないことがわかっているため、許可されています。
ここにいくつかの議論がありますが、それでもまだわかりませんが、前よりも一貫しています。https://github.com/rust-lang/rust/issues/32433 – WiSaGaN