2015-08-26 12 views
5

Sono nuovo di ruggine e ho ancora qualche problema con la proprietà/il prestito. In questo caso, voglio memorizzare un FnOnce in un enum e poi chiamarlo in seguito da un altro thread. Ho provato molte varianti diverse ma sono sempre rimasto bloccato da qualche parte. Ecco una ridotta variante di quello che ho attualmente:FnOnce all'interno di Enum: non può uscire dal contenuto preso in prestito

#![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(); 
} 

io uso "rustc 1.4.0-serale (e35fd7481 2015/08/17)". Il messaggio di errore:

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

Da quanto ho capito, f è di proprietà della enum nella mutex e ho solo prendere in prestito tramite * foo. Ma per chiamare f, ho bisogno di spostarlo. Ma come farlo? O cos'altro devo cambiare per far funzionare questo esempio?

risposta

7

std::mem::replace è quello che si dovrebbe usare lì, in questo modo:

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

di riferimento Documentazione: [std :: :: mem sostituire] (http://doc.rust-lang.org/std/mem/ fn.replace.html) –

+0

Puoi spiegare di più perché non ha funzionato in primo luogo? Perché 'f' deve essere spostato? – tafia

+0

@tafia: 'FnBox' è basato su' FnOnce', che consuma l'ambiente di chiusura; cioè, 'f.call_box' prende' self' per valore, quindi 'f' deve essere' Box '. Un riferimento mutabile a quello non sarà sufficiente, e un riferimento mutabile è tutto ciò che avevi nel tuo esempio iniziale (quindi "non può uscire dal contesto preso in prestito", sta cercando di spostare il 'Box ' di un riferimento mutevole). –

Problemi correlati