2015-08-26 7 views
5

Ich bin neu zu rosten und habe immer noch einige Probleme mit dem Besitz/Ausleihen. In diesem Fall möchte ich eine FnOnce in einer Enum speichern und sie später von einem anderen Thread aufrufen. Ich habe viele verschiedene Varianten ausprobiert, bin aber immer irgendwo steckengeblieben. Hier ist eine reduzierte Variante dessen, was ich derzeit haben:FnOnce in Enum: kann nicht ausgeliehenen Inhalt bewegen

#![feature(fnbox)] 

use std::sync::{Arc, Mutex}; 
use std::boxed::{Box, FnBox}; 

enum Foo<T> { 
    DoNothing, 
    CallFunction(Box<FnBox(&T) + Send>) 
} 

struct FooInMutex<T> { 
    foo: Arc<Mutex<Foo<T>>> 
} 

impl<T> FooInMutex<T> { 
    fn put_fn(&self, f: Box<FnBox(&T)+Send>) { 
     let mut foo = self.foo.lock().unwrap(); 
     let mut new_foo : Foo<T>; 
     match *foo { 
      Foo::DoNothing => 
       new_foo = Foo::CallFunction(f), 
      _ => 
       new_foo = Foo::DoNothing 
     } 
     *foo = new_foo; 
    } 

    fn do_it(&self, t: T) { 
     let mut foo = self.foo.lock().unwrap(); 
     let mut new_foo : Foo<T>; 
     match *foo { 
      Foo::CallFunction(ref mut f) => { 
       //f(&t) 
       f.call_box((&t,)); 
       new_foo = Foo::DoNothing; 
      } 
      _ => 
       panic!("...") 
     } 
     *foo = new_foo; 
    } 
} 

#[test] 
fn it_works() { 
    let x = FooInMutex { foo: Arch::new(Mutex::new(Foo::DoNothing)) }; 

    x.put_fn(Box::new(|| panic!("foo"))); 
    x.do_it(); 
} 

Ich benutze "rustc 1.4.0-nächtlichen (e35fd7481 2015.08.17)". Die Fehlermeldung:

src/lib.rs:35:17: 35:18 error: cannot move out of borrowed content 
src/lib.rs:35     f.call_box((&t,)); 
          ^

Wie ich es verstehe, f durch die Enum in der Mutex gehört und ich kann es nur über * foo ausleihen. Aber für den Aufruf f muss ich es verschieben. Aber wie geht das? Oder was muss ich noch ändern, damit dieses Beispiel funktioniert?

Antwort

7

std::mem::replace ist, was Sie es verwenden sollten, wie folgt aus:

use std::mem; 

… 

    fn do_it(&self, t: T) { 
     match mem::replace(self.foo.lock().unwrap(), Foo::DoNothing) { 
      Foo::CallFunction(f) => { 
       f.call_box((&t,)); 
      } 
      _ => panic!("...") 
     } 
    } 
+0

Dokumentation Hinweis: [std :: mem :: ersetzen] (http://doc.rust-lang.org/std/mem/ fn.replace.html) –

+0

Können Sie mehr erklären, warum es überhaupt nicht funktioniert hat? Warum muss "f" ausgezogen werden? – tafia

+0

@tafia: 'FnBox' basiert auf' FnOnce', was die Closure-Umgebung verbraucht; Das heißt, 'f.call_box' nimmt' self' nach Wert, also muss 'f'' Box 'sein. Ein veränderlicher Hinweis darauf wird nicht ausreichen, und eine veränderbare Referenz ist alles, was Sie in Ihrem anfänglichen Beispiel hatten (daher "kann sich nicht aus dem geliehenen Kontext bewegen"), es versucht, die 'Box aus zu verschieben eine veränderbare Referenz). –

Verwandte Themen