以下のコードに出くわす前に、型の有効期間パラメーターの有効期間は、常にそれ自体のインスタンスよりも長生きすると確信していました。つまり、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
の(より短い)存続期間に強制変換できるため、それを受け入れることができます。