2015-01-13 4 views
5

Verwendung habe ich ein Problem mit dem Checker borrow, wenn Zügen als Typparameter in einer Struktur mit:Borrow Prüfung versagt, wenn Züge als Typ-Parameter

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") 
} 

Die Ausgabe lautet:

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") 
^ 

Doch die folgendes Beispiel funktioniert:

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); 
    } 
} 

Das sieht wirklich komisch aus, denn das zweite Beispiel ist nur ein Instanti des ersten Beispiels, und ich könnte wahrscheinlich (schmerzlich) dasselbe mit Makros implementieren.

Ich denke, das ziemlich schwierig ist, da ich den Typen der von der Schließung genommen Parameter muß wissen, aber ich brauche nicht diese Referenz zu speichern ...

Ist das ein Fehler in den borrow Checker? Oder mache ich etwas falsch?

rustc 1.0.0-nightly (44a287e6e 2015-01-08 17:03:40 -0800) 

EDIT 1: präzisierte der Anwendungsfall

EDIT 2: Wie unten in der Antwort erläutert, ist das Problem, dass die borrow checker die Lebensdauer von Observer<&mut Type> zwingt die gleiche wie die &mut Type zu sein, also in Tatsache ist, dass das Problem nicht damit zusammenhängt, dass wir ein Merkmal als Typparameter verwenden (dasselbe gilt für eine tatsächliche Struktur).
Also in meinem Fall kann ich durch die Definition Observer<Arg> wie diese eine Abhilfe haben:

struct Observer<Arg> { 
    action: Box<Fn(&mut Arg) + Send>, 
} 

so der Typ-Parameter Arg selbst keine Referenz ist, aber das macht den Code weniger generisch. Hat jemand eine bessere Lösung?

Antwort

3

Das Problem hier ist, dass der Borrow-Checker die Lebensdauer der &mut Trait Referenz auf die gleiche wie die gesamte GenericStruct erzwingt. Ich glaube, das liegt daran, dass die Referenz ein Typparameter der Struktur selbst ist.

Da Ihre Struktur keine Felder enthält, die die Referenz speichern (wenn Sie dies in Ihrem ursprünglichen Code tun müssen, aktualisieren Sie bitte Ihre Frage), dann können Sie den Typparameter in die Methode selbst statt der Struktur verschieben:

trait Trait{} 

struct FooBar; 
impl Trait for FooBar{} 

struct GenericStruct; 

impl GenericStruct { 
    fn bar<T>(&self, _: T) {} 
} 

fn main() { 
    let mut foobar = FooBar; 

    { 
     let foo = GenericStruct; 
     foo.bar(&mut foobar); 
     foo.bar(&mut foobar); 
    } 
} 

Dies wird den Kredit nur so lange dauern, wie der Anruf an foo.bar().

Verwandte Themen