web-dev-qa-db-ja.com

このインスタンスは、どのようにしてそれ自体のパラメータの有効期間よりも長生きすることができますか?

以下のコードに出くわす前に、型の有効期間パラメーターの有効期間は、常にそれ自体のインスタンスよりも長生きすると確信していました。つまり、foo: Foo<'a>が与えられると、'aは常にfooよりも長生きします。それから私は@LucDanton( Playground )によってこの反論コードを紹介されました:

#[derive(Debug)]
struct Foo<'a>(std::marker::PhantomData<fn(&'a ())>);

fn hint<'a, Arg>(_: &'a Arg) -> Foo<'a> {
    Foo(std::marker::PhantomData)
}

fn check<'a>(_: &Foo<'a>, _: &'a ()) {}

fn main() {
    let outlived = ();
    let foo;

    {
        let shortlived = ();
        foo = hint(&shortlived);
        // error: `shortlived` does not live long enough
        //check(&foo, &shortlived);
    }

    check(&foo, &outlived);
}

fooによって作成されたhintは、それ自体が長く存続しない存続期間を考慮しているように見え、それへの参照がより広いスコープの関数に渡されますが、コードはコンパイルされますそのままです。コードに記述されている行のコメントを解除すると、コンパイルエラーが発生します。または、FooをstructTuple (PhantomData<&'a ()>)に変更すると、同じ種類のエラー( Playground )でコードがコンパイルされなくなります。

それはどのように有効ですかRustコード?ここでのコンパイラの理由は何ですか?

これを説明する別の方法は、Fooが実際には'aの存続期間を持つものへの参照を保持していないことに注意することです。むしろ、accepts存続期間'aの参照を保持する関数を保持します。

PhantomDataの代わりに、実際の関数を使用してこれと同じ動作を構築できます。そして、その関数を呼び出すこともできます。

struct Foo<'a>(fn(&'a ()));

fn hint<'a, Arg>(_: &'a Arg) -> Foo<'a> {
    fn bar<'a, T: Debug>(value: &'a T) {
        println!("The value is {:?}", value);
    }
    Foo(bar)
}

fn main() {
    let outlived = ();
    let foo;
    {
        let shortlived = ();
        // &shortlived is borrowed by hint() but NOT stored in foo
        foo = hint(&shortlived);
    }
    foo.0(&outlived);
}

フランシスが彼の優れた回答で説明したように、outlivedのタイプは、寿命が長いため、shortlivedのタイプのサブタイプです。したがって、foo内の関数は、shortlivedの(より短い)存続期間に強制変換できるため、それを受け入れることができます。

3
Peter Hall