3

さびた生涯はまた私を混乱させます。所有しているボックス化されたオブジェクトへの変更可能な参照を返そうとしています。これが私の問題を単純化したものです:

pub trait Foo {
    fn foo(&self);
}

pub struct Bar {
    foo: Option<Box<Foo>>,
}

impl Bar {

    pub fn foo(&mut self) -> &mut Box<Foo> {
        let foo_ref = self.foo.as_mut();
        foo_ref.unwrap()
    }

    pub fn set_foo(&mut self, value: Box<Foo>) {
        self.foo = Some(value);
    }
}

これらのエラーが表示されますが、よくわかりません。

   Compiling testproject v0.0.1 (file:///home/virtlink/projects/orion/testproject)
src/lib.rs:15:17: 15:25 error: cannot infer an appropriate lifetime due to conflicting requirements
src/lib.rs:15         foo_ref.unwrap()
                              ^~~~~~~~
src/lib.rs:15:9: 15:25 note: first, the lifetime cannot outlive the method call at 15:8...
src/lib.rs:15         foo_ref.unwrap()
                      ^~~~~~~~~~~~~~~~
src/lib.rs:15:9: 15:16 note: ...so that method receiver is valid for the method call
src/lib.rs:15         foo_ref.unwrap()
                      ^~~~~~~
src/lib.rs:13:44: 16:6 note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the block at 13:43...
src/lib.rs:13     pub fn foo(&mut self) -> &mut Box<Foo> {
src/lib.rs:14         let foo_ref = self.foo.as_mut();
src/lib.rs:15         foo_ref.unwrap()
src/lib.rs:16     }
src/lib.rs:15:9: 15:25 note: ...so that expression is assignable (expected `&mut Box<Foo>`, found `&mut Box<Foo>`)
src/lib.rs:15         foo_ref.unwrap()
                      ^~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `testproject`.

これを解決する方法がわかりません。

4

1 に答える 1

11

これは生涯の省略のケースであり、デフォルトのオブジェクトは非常に目に見えない方法で逆火を制限します。

エラーはそのままではまったく不透明であり、これは良くありません。.as_mut().unwrap()を同等のmatchステートメントに置き換えると、次のようになります。

match self.foo {
    Some(ref mut foo) => foo,
    None => panic!(),
}

物事が少し明確になります:

a.rs:13:34: 13:37 error: mismatched types:
 expected `&mut Box<Foo>`,
    found `&mut Box<Foo>`
(lifetime mismatch) [E0308]
a.rs:13             Some(ref mut foo) => foo,
                                         ^~~
a.rs:11:44: 16:6 note: the anonymous lifetime #1 defined on the block at 11:43...
a.rs:11     pub fn foo(&mut self) -> &mut Box<Foo> {
a.rs:12         match self.foo {
a.rs:13             Some(ref mut foo) => foo,
a.rs:14             None => panic!(),
a.rs:15         }
a.rs:16     }
note: ...does not necessarily outlive the static lifetime
error: aborting due to previous error

これで、 type のどこかでライフタイムの不一致が発生し&mut Box<Foo>ていること、匿名のライフタイムが静的なライフタイムよりも長生きするとは限らないことがわかりました。そのタイプには 2 つのライフタイムがあります。型省略がない場合、その型は&'a mut Box<Foo + 'b>. 特性オブジェクトでは、特性オブジェクトが存続できる期間を示す必要があることを忘れないでください'b。最も一般的なケースでBox<Trait>は、 は に相当しBox<Trait + 'static>ます。これは、特性オブジェクトに非静的参照を含めることができないことを示します。(この保証がなければ、メモリの安全性に違反します。) 構造体の定義では、特性オブジェクトの有効期間は次のように推測さ'staticれます。

ただし、省略された有効期間Box<Trait>が常に と解釈されるとは限りません'static。参照に含まれている場合、必要な有効期間はそれに短縮されます。つまり、&'a Box<Trait>として解釈され&'a Box<Trait + 'a>ます。

したがって、メソッドの完全な省略なしの署名は、実際には次のようになります。

pub fn foo<'a>(&'a mut self) -> &'a mut Box<Foo + 'a>;

なぜこれがうまくいかないのか、私にはよくわかりません。&'a mut Box<Foo + 'static>a (あなたが持っている)を a に強制できると思っていたでしょうが&'a mut Box<Foo + 'a>、明らかにそうではありません。差異処理のバグである可能性があります (合法であるはずのコードを拒否する) か、そうでない可能性があります。よくわかりません。匿名のライフタイム #1 が静的なライフタイムよりも長生きする必要がある理由がわかりません。そのエラーは、ライフタイムを前後に処理しているように感じます。

とにかく、あなたが実際に望んでいたのは、 を返すことでした&'a mut Box<Foo + 'static>。したがって、'static明示的に out を書き出すだけで、すべておかしなものになります。

pub fn foo(&mut self) -> &mut Box<Foo + 'static> {
    self.foo.as_mut().unwrap()
}

Foo別の解決策は、実装する型が常に である必要があることを定義で要求すること'staticです。その場合、必ずしも ほど大きくないBox<Foo + 'a>にとっては明らかにナンセンスであり、賢明になり、それが である必要があることを認識します。(特性に対する有効期間の制約は、デフォルトのオブジェクト境界をオーバーライドします。)'a'static'static

デフォルトのオブジェクト境界について詳しくは、RFC 599を参照してください。

于 2015-04-13T13:37:12.617 に答える