Was ist in Rust "fn () -> ()"?

Oct 10 2020

Ich habe ein Gespür für die Fn (Hauptstadt-F) Merkmale: Fn, FnMut, FnOnce. Ich verstehe, dass sie Eigenschaften sind und wie Eigenschaften funktionieren.

Aber was ist mit fn(Kleinbuchstaben-f)? In den Editoren erhält es eine andere Farbe, was mir sagt, dass es kein Merkmal ist. Es kann auch an einigen Stellen verwendet werden, an denen die anderen dies nicht können (und umgekehrt), obwohl es sich in anderen Fällen ähnlich zu verhalten scheint. Ich konnte nichts finden, was es direkt in den Dokumenten erklärt.

Antworten

8 trentcl Oct 10 2020 at 22:09

Die Antwort von prog-fh ist im Wesentlichen richtig, aber es fehlt eine Nuance. Rust hat drei Arten von funktionsähnlichen Typen:

  1. Funktionselemente erhalten Sie, wenn Sie mithilfe von eine Funktion erstellenfn foo() {...}. Es ist auch der Typ des Konstruktors einer tupelartigen Struktur oder Enum-Variante. Funktionselemente haben die Größe Null (sie enthalten keine Daten), und jede nicht generische Funktion verfügt über einen eindeutigen, nicht benennbaren Funktionselementtyp. In Fehlermeldungen zeigt der Compiler diese "Voldemort-Typen" wie folgt anfn() -> () {foo}(mit dem Namen der Funktion in{}).

  2. Verschlüsse sind Werte ähnlich wie Funktionselemente, aber Verschlüsse können Daten enthalten: Kopien oder Verweise auf was auch immer Variablen sie aus ihrer Umgebung erfassen. Wie Sie bereits wissen, erstellen Sie einen Abschluss mithilfe der Abschlusssyntax (|args| expression). Verschlüsse haben wie Funktionselemente eindeutige, nicht benennbare Typen (vom Compiler so ähnlich gerendert[closure@src/main.rs:4:11: 4:23]).

  3. Funktionszeiger sind das, wonach Sie fragen: die Typen, die aussehenfn() -> (). Funktionszeiger können keine Daten enthalten, haben jedoch keine Größe von Null. Wie der Name schon sagt, sind sie Zeiger. Ein Funktionszeiger kann entweder auf ein Funktionselement oder auf einen Abschluss verweisen, der nichts erfasst, aber nicht null sein.

Funktionselemente und Abschlüsse werden nach Möglichkeit automatisch auf den entsprechenden Funktionszeigertyp gezwungen. Deshalb let f: fn(i32) = |_| ();funktioniert dies: Da der Abschluss nichts erfasst, kann er zu einem Funktionszeiger gezwungen werden.

Alle drei funktionsähnliche Typen implementieren die relevant Fn, FnMutund FnOnceZüge (außer dass Verschlüsse möglicherweise nicht implementieren Fnoder FnMutje nachdem , was sie capture). Funktionselemente und Funktionszeiger implementieren auch Copy, Clone, Sendund Sync(Schließungen nur diese Merkmale implementieren , wenn alle ihren Inhalt zu tun).

In Bezug auf die Leistung sind Funktionszeiger ein Kompromiss zwischen Generika und Merkmalsobjekten. Sie müssen dereferenziert werden, um aufgerufen zu werden. Daher kann das Aufrufen eines Funktionszeigers langsamer sein als das direkte Aufrufen eines Funktionselements oder Abschlusses, aber immer noch schneller als das Aufrufen eines dyn FnMerkmalsobjekts, bei dem zusätzlich zum indirekten Aufruf eine vtable-Suche durchgeführt wird.

Verweise

  • Was ist der praktische Unterschied zwischen fn item und fn pointer?
  • Warum eine Sprache mit eindeutigen anonymen Typen entwerfen?
  • Wie erstelle ich eine Struktur für FFI, die einen nullbaren Funktionszeiger enthält?
  • Warum funktioniert es nicht, einen Abschluss an eine Funktion zu übergeben, die einen Funktionszeiger akzeptiert?
3 prog-fh Oct 10 2020 at 21:07

Es ist ein Funktionszeigertyp .

Es bezieht sich nur auf eine Funktion, nicht auf einen Abschluss, da es nur die Adresse der Funktion enthält, nicht die erfasste Umgebung, die ein Abschluss benötigt.

Ein FnMerkmal (Großbuchstabe F) kann sich entweder auf einen Abschluss oder eine Funktion beziehen.

NickDecroos Oct 10 2020 at 21:07

fn ist der Typ für einen Funktionszeiger. Siehe auch hier in der Dokumentation:https://doc.rust-lang.org/std/primitive.fn.html