2016-03-25 6 views
3

Hier ist ein Beispiel von Rust by Example:Warum sollten Sie `FnMut` verwenden, wenn das Argument nach Wert genommen wird?

pub trait Iterator { 
    // The type being iterated over. 
    type Item; 

    // `any` takes `&mut self` meaning the caller may be borrowed 
    // and modified, but not consumed. 
    fn any<F>(&mut self, f: F) -> bool where 
     // `FnMut` meaning any captured variable may at most be 
     // modified, not consumed. `Self::Item` states it takes 
     // arguments to the closure by value. 
     F: FnMut(Self::Item) -> bool {} 
} 

Warum FnMut plagt, zu verwenden, wenn das Argument von Wert genommen wird, da das Argument nicht sowieso mutiert werden kann? In der Tat, warum ist FnMut sogar hier erlaubt? Es scheint nur FnOnceis permitted to do this:

Es wurde festgestellt, dass Rust wählt, wie Variablen auf dem fly ohne Anmerkung zu erfassen. Dies ist in der normalen Verwendung sehr praktisch , aber beim Schreiben von Funktionen ist diese Mehrdeutigkeit nicht erlaubt. Der vollständige Typ des Abschlusses , einschließlich des Erfassungstyps, muss kommentiert sein.

  • Fn:: durch Verweis (&T) hat Captures
  • FnMut: nimmt Captures durch veränderbare Referenz (&mut T)
  • FnOnce Die Art und Weise der Erfassung ein Verschluss verwendet, wie ein von folgenden trait s ist kommentieren : nimmt Aufnahmen von Wert (T)
+0

Was meinen Sie mit "das Argument wird von Wert genommen"? Sprechen Sie über 'f: F'? –

+0

Ja. F nimmt Argument nach Wert. – qed

+0

Können Sie erklären, was Sie tun sollten, anstatt 'FnMut' zu verwenden? –

Antwort

4

Die Unterscheidung zwischen FnOnce, FnMut und Fn ist, wie die Funktion auf ihre Umgebung zugreift (Verschiebung, veränderbare Referenz, gemeinsame Referenz). Es hat nichts damit zu tun, auf die Argumente der Funktion zuzugreifen.

FnMut wird hier benötigt, da die any-Methode die Funktion möglicherweise mehrmals aufrufen muss.

Es gibt eine paragraph in the Rust book about the implementation of closures. Es zeigt die Unterschiede in dem self Argument, das im Wesentlichen ein struct ist, das die Umgebung enthält.

1

Warum sollten Sie FnMut verwenden, wenn das Argument wertmäßig verwendet wird, da das arg sowieso nicht mutiert werden kann?

Das Beispiel Sie Art falsch ist verbunden, da die Methodendefinition sollte wie folgt aussehen:

fn any<F>(&mut self, mut f: F) -> bool // note the `mut f: F` 
    where F: FnMut(Self::Item) -> bool {} 

(vergleiche the std implementation)

Diese Änderung ändert sich jedoch nicht, wie die any Methode kann verwendet werden! Die mut ist nur Teil der Variablenbindung (die nur für die Methode impl wichtig ist) und nicht Teil des Typs. Wenn wir etwas nach Wert nehmen, haben wir die vollständige Kontrolle über die Variable - wenn wir die Variable mutieren wollen, können wir das tun, aber wir müssen sie veränderlich binden.


In der Tat, warum FnMut auch hier erlaubt?

Sie können Eigenschaft haben begrenze dass würde alle Arten von Operationen mit einer Art erlauben, auch wenn Sie nicht diese Operationen aufgrund fehlender Zugriff auf die Variable verwenden können. Siehe:

fn foo<T: Iterator<Item=i32>>(it: &T) {} 

Dies ist gültig, aber nicht sinnvoll, denn sobald Sie etwas Brauchbares mit dem Iterator tun wollen (wie der Aufruf next):

it.next(); 

Sie einen Compiler-Fehler erhalten, da Sie eine &mut self Methode auf einen unveränderlichen Kredit nicht anrufen können. Das von Ihnen verlinkte Beispiel funktioniert also nur, weil der Funktionskörper nicht die Funktionalität FnMut verwendet.

Verwandte Themen