2015-05-23 2 views
7
bewegen

Ich versuche, einige höhere Ordnung Programmierung in Rust zu tun, aber ich einige Schwierigkeiten mit Schließungen zu tun habe. Hier ist ein Code-Snippet, das eines des Problems zeigt Ich habe:„kann nicht einen Wert vom Typ FnOnce bewegen“, wenn eine geschachtelte Funktion

pub enum Foo { 
    Bar(Box<FnOnce(i32)>), 
} 

pub fn app(i: i32, arg: Foo) { 
    match arg { 
     Foo::Bar(f) => f(i), 
    } 
} 

Als ich dieses Stück Code zu kompilieren bekomme ich folgende Fehlermeldung:

error[E0161]: cannot move a value of type std::ops::FnOnce(i32) + 'static: the size of std::ops::FnOnce(i32) + 'static cannot be statically determined 
--> src/main.rs:7:24 
    | 
7 |   Foo::Bar(f) => f(i), 
    |      ^

Da ich die Funktion in einem setzen Box, hätte ich gedacht, dass das mit dem Problem des Compilers umgehen würde, die Größe nicht zu kennen. Wie kann ich das obige Programm kompilieren?

Antwort

11

Hier ist die FnOnce Definition des Merkmals (vereinfacht ein wenig):

pub trait FnOnce<Args> { 
    type Output; 

    fn call_once(self, args: Args) -> Self::Output; 
} 

einen FnOnce Verschluss anzurufen, müssen Sie den Verschlusswert selbst in die Anrufung der Lage sein, zu bewegen. Beachten Sie, dass self der tatsächliche Verschlusstyp sein muss; Ein Box<FnOnce> ist ein ganz anderer Typ.

Als Ergebnis ist es mehr oder weniger unmöglich.

Jetzt ist ein Typ in der Standardbibliothek für den Umgang mit nur dieser Situation: FnBox. Leider, es ist erst vor kurzem hinzugefügt worden ist, und somit kann nicht in stabiler Rust noch verwendet werden (das ist der „oder weniger“ Teil).

Also, haben Sie folgende Möglichkeiten:

  • Umgestalten der Code so, dass anstelle von Box<FnOnce>, können Sie die Verschlusstyp tatsächlichen bewahren.
  • Verwenden Sie stattdessen Box<FnMut>.
  • Warten Sie, bis sich FnBox stabilisiert hat.
  • Wechseln Sie zu einem nächtlichen Compiler.
+0

Vielen Dank für das answer.Using des tatsächliche Verschlusstyp für mich keine Option ist, da ich verschiedene Schließungen in der Enum speichern können müssen. Ich weiß nicht, wie man den "Box " Vorschlag funktioniert, ich bekomme einen Fehler, wenn ich das versuche. Was ich stattdessen geschafft habe, ist einfach "Box " zu sagen. Das hat mir geholfen, das obige Beispiel zu erstellen. Allerdings kann ich mit diesem Typ keine Enumeration erstellen, da sie nicht mit dem Typ der Schließung übereinstimmt. Ich denke also, ich muss einen nächtlichen Compiler ausprobieren. – svenningsson

+0

@svenningsson: Stattdessen "Box " verwenden; Da 'FnMut' 'objektsicher' ist, kann * man einen durch eine' Box' (oder irgendeine indirekte Richtung) aufrufen.Das einzige, was Sie nicht tun können, ist, dass die Closure-Werte verbraucht werden (obwohl Sie das mit "Option" umgehen können). –

+0

Der Fehler, den ich bekomme, wenn ich 'Box ' versuche, ist folgender: kann unveränderlichen 'Box' Inhalt' * f 'nicht als veränderlich ausleihen src/lib.rs: 36 Foo :: Bar (f) => f (i) – svenningsson

0

Es ist unwahrscheinlich, FnBox stabil wird, aber zur Zeit können Sie die F: FnOnce(...) -> ... in einem Option<F> wickeln, binden sie in einem wandelbaren Verschluss und auspacken und es innen nennen (so in Panik gerät es, wenn es mehr als einmal aufgerufen wird); Die resultierende Schließung kann als Box<FnMut(...) -> ...> Box eingerahmt werden, die Sie irgendwie wickeln möchten, um sicherzustellen, dass es nur einmal verwendet ("genannt") wird.

See (my) boxfnonce Kiste.

Verwandte Themen