構造体の型パラメーターとして特性を使用する場合、借用チェッカーに問題があります。
trait Trait {}
struct FooBar;
impl Trait for FooBar{}
struct Observer<Arg> {
action: Box<Fn(Arg) + Send>,
// Other fields
}
impl <Arg> Observer<Arg> {
fn new(action: Box<Fn(Arg) + Send>) -> Observer<Arg> {
Observer{action: action}
}
fn execute(&self, arg: Arg) {
(*self.action)(arg);
}
}
fn test() {
let mut foobar = FooBar;
{
let mut observer = Observer::new(Box::new(|&: param: &mut Trait| {
// do something with param here
}));
observer.execute(&mut foobar); // First borrow passes ...
observer.execute(&mut foobar); // This fails as "foobar" is already borrowed
} // The previous borrow ends here (lifetime of "observer")
}
出力は次のとおりです。
error: cannot borrow `foobar` as mutable more than once at a time
observer.execute(&mut foobar); // This fails as "foobar" is already borrowed
^~~~~~
note: previous borrow of `foobar` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foobar` until the borrow ends
observer.execute(&mut foobar); // First borrow passes ...
^~~~~~
note: previous borrow ends here
{
...
} // The previous borrow ends here (lifetime of "observer")
^
それでも、次の例は機能します。
trait Trait {}
struct FooBar;
impl Trait for FooBar{}
struct Observer {
action: Box<Fn(&mut Trait) + Send>,
// Other fields
}
impl Observer {
fn new(action: Box<Fn(&mut Trait) + Send>) -> Observer {
Observer{action: action}
}
fn execute(&self, arg: &mut Trait) {
(*self.action)(arg);
}
}
fn test() {
let mut foobar = FooBar;
{
let mut observer = Observer::new(Box::new(|&: param: &mut Trait| {
// do something with param here
}));
observer.execute(&mut foobar);
observer.execute(&mut foobar);
}
}
2 番目の例は 1 番目の例のインスタンス化にすぎないため、これは私には非常に奇妙に見えますが、マクロを使用して同じことを (苦労して) 実装できる可能性があります。
クロージャーが受け取るパラメーターの型を知る必要があるため、これは非常に難しいと思いますが、この参照を保存する必要はありません...
これは借用チェッカーのバグですか? それとも私は何か間違ったことをしていますか?
rustc 1.0.0-nightly (44a287e6e 2015-01-08 17:03:40 -0800)
編集1:ユースケースを正確に
編集 2: 以下の回答で説明されているように、問題は、借用チェッカーが の有効期間をObserver<&mut Type>
と同じにすることを強制する&mut Type
ことです。そのため、実際には、問題は型パラメーターとしてトレイトを使用するという事実とは関係ありません (実際の構造でも同じことを行います)。
したがって、私の場合、次のObserver<Arg>
ように定義することで回避策を講じることができます。
struct Observer<Arg> {
action: Box<Fn(&mut Arg) + Send>,
}
したがって、型パラメーター Arg 自体は参照ではありませんが、これによりコードの汎用性が低くなります。誰もがより良い解決策を持っていますか?