1. ホーム
  2. reference

[解決済み】なぜRustでは明示的なライフタイムが必要なのですか?

2022-04-02 09:25:47

質問

を読んでいたのですが ライフタイム編 で、名前付き/明示的なライフタイムの例として、こんなのを見つけました。

struct Foo<'a> {
    x: &'a i32,
}

fn main() {
    let x;                    // -+ x goes into scope
                              //  |
    {                         //  |
        let y = &5;           // ---+ y goes into scope
        let f = Foo { x: y }; // ---+ f goes into scope
        x = &f.x;             //  | | error here
    }                         // ---+ f and y go out of scope
                              //  |
    println!("{}", x);        //  |
}                             // -+ x goes out of scope

コンパイラが防いでいるエラーは、かなり明確に ユーズアフターフリー に割り当てられた参照の x : 内部スコープが終了した後。 f であるため &f.x は無効となり、割り当てられるべきではありませんでした。 x .

私の問題は、この問題が簡単に分析されなくなる可能性があったということです なく を使用しています。 明示的 'a のライフタイム、例えば、より広いスコープへの参照の不正な割り当てを推論することで ( x = &f.x; ).

use-after-free(または他のクラス?)エラーを防ぐために、どのような場合に明示的な寿命が実際に必要なのでしょうか?

どのように解決するのですか?

他の回答は、いずれも鋭い指摘がある( 明示的なライフタイムが必要なfjhの具体例 の場合、なぜ明示的なライフタイムが必要なのか? コンパイラは、あなたが間違っていることを教えてくれます。 ?

これは実は、「コンパイラが推論できるのに、なぜ明示的な型が必要なのか」という質問と同じです。仮定的な例です。

fn foo() -> _ {  
    ""
}

もちろん、コンパイラは、私が &'static str では、なぜプログラマーはそれをタイプしなければならないのでしょうか?

主な理由は、コンパイラーはあなたのコードが何をするかはわかりますが、あなたの意図が何であったかはわからないからです。

関数は、コードを変更したときの影響をファイアウォールで防ぐための自然な境界線です。もし、ライフタイムをコードから完全に検査できるようにすると、無害に見える変更がライフタイムに影響を与え、それが遠くの関数でエラーを引き起こす可能性があります。これは仮説の例ではありません。私の理解では、Haskellはトップレベル関数の型推論に依存する場合にこの問題が発生する。Rustはこの問題の芽を摘み取ったのです。

また、コンパイラにとっても効率的な利点があります。型と寿命を検証するために解析する必要があるのは、関数のシグネチャだけです。さらに重要なのは、プログラマーにとっても効率的な利点があることです。もし、明示的なライフタイムがなかったら、この関数は何をするのだろう。

fn foo(a: &u8, b: &u8) -> &u8

ソースを検査しない限り、コーディングのベストプラクティスに反してしまうので、判断は不可能です。

<ブロッククオート

より広いスコープへの参照の不正な割り当てを推論することによって

スコープ ライフタイム、基本的に。もう少し分かりやすく言うと、一生は 'a 汎用ライフタイムパラメータ は、コンパイル時に呼び出し元のサイトに応じて特定のスコープに特化させることができます。

<ブロッククオート

明示的なライフタイムは、[...]エラーを防ぐために実際に必要なのでしょうか?

そんなことはありません。 ライフタイム はエラーを防ぐために必要ですが、プログラマのわずかな正気を守るために、明示的なライフタイムが必要です。