2017-02-22 5 views
4

Ich versuche, eine Schließung, die ein &Any als Argument zurückgibt. Der folgende Code gibt einen Compilerfehler zurück.Nicht-skalare Besetzung: `Box <FnMut<&Any>>`

trait Selector { 
    fn id(&self) -> i64; 
    fn selector(&self) -> Box<FnMut(&Any, &mut Any)>; 
} 
struct TypedSelector<TSource, TTarget> { 
    id: i64, 
    select: Box<FnMut(&TSource, &mut TTarget)>, 
} 
impl<TSource, TTarget> Selector for TypedSelector<TSource, TTarget> 
    where TSource: 'static, 
      TTarget: 'static 
{ 
    fn id(&self) -> i64 { 
     self.id 
    } 
    fn selector(&self) -> Box<FnMut(&Any, &mut Any)> { 
     self.select as Box<FnMut(&Any, &mut Any)> 
    } 
} 

Der Compiler-Fehler ist folgende:

error: non-scalar cast: `Box<for<'r, 'r> std::ops::FnMut(&'r TSource, &'r mut TTarget) + 'static>` as `Box<for<'r, 'r> std::ops::FnMut(&'r std::any::Any + 'static, &'r mut std::any::Any + 'static)>` 
    --> src\main.rs:190:9 
    | 
190 |   self.select as Box<FnMut(&Any, &mut Any)> 
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Bin ich ein paar Typenannotationen fehlt?

Antwort

4

Es gibt ein paar Probleme hier.

Zuerst, was Sie versuchen zu tun (Cast von FnMut<&TSource, &mut TTarget> bis FnMut<&Any, &mut Any>) ist nicht gültig. Wenn Sie erfolgreich gewesen wären, hätten Sie eine Funktion aufrufen können, die eine &TSource mit einem anderen Typ erwartet - also hätten Sie die Typsicherheit gebrochen und ein undefiniertes Verhalten verursacht.

Um dies zu beheben, können Sie es in einem Verschluss wickeln, die die Any downcasts und behandelt alle Fehler (in diesem Beispiel wird es panic wie ich unwrap verwenden):

Box::new(
     move |a, b| { 
      let a = a.downcast_ref().expect("a was the wrong type."); 
      let b = b.downcast_mut().expect("b was the wrong type."); 
      (self.select)(a, b) 
     } 
    ) 

An dieser Stelle das nächste Problem wird Scheinbar: TypedSelector besitzt das Original Boxed Verschluss (select), aber diese neue Schließung braucht Zugriff darauf. Es gibt drei Möglichkeiten, Werte in Rust, und keine Arbeit passieren wie:

  • von Wert (move) wird nicht funktionieren, es sei denn, selector nimmt self nach Wert (und damit zerstört sie im Prozess)
  • von unveränderlich &reference würde nicht erlauben, die FnMut
  • durch mutable &mut reference anrufen kann in ähnlicher Weise nicht von der unveränderlichen &self getan werden.

So etwas muss sich ändern. Ich werde willkürlich die am besten ausgestattete, aber schwergewichtigste Option auswählen und Rc<RefCell<T>> verwenden, um Referenzzähler für die intern veränderbaren FnMut freigegeben zu haben; dies ist vielleicht nicht die Option, die am besten für Ihre Situation ist:

fn selector(&self) -> Box<FnMut(&Any, &mut Any)+'static> { 
    let wrapped = self.select.clone(); 
    Box::new(
     move |a, b| { 
      let a = a.downcast_ref().expect("a was the wrong type."); 
      let b = b.downcast_mut().expect("b was the wrong type."); 

      // Mutably borrow the shared closure (checked at runtime) 
      let mut f = wrapped.borrow_mut(); 

      (&mut *f)(a, b) 
     } 
    ) 
    //self.select as Box<FnMut(&Any, &mut Any)> 
} 

(Playground link)

+0

Ich weiß, was 'unwrap' verlockend ist, aber es könnte am besten sein, Neulinge zu lehren' statt expect' zu verwenden. Es macht schließlich diagnostizieren, was schief gelaufen ist. –

+0

@MatthieuM. Guter Punkt, aktualisiert. –

Verwandte Themen