Dans Rust, qu'est-ce que `fn () -> ()`?

Oct 10 2020

J'ai une bonne connaissance des traits Fn (capital F): Fn, FnMut, FnOnce. Je comprends que ce sont des traits et qu'ils fonctionnent comme des traits.

Mais qu'en est-il fn(f minuscule)? Il prend une couleur différente dans les éditeurs, ce qui me dit que ce n'est pas un trait. Il peut également être utilisé dans certains endroits où les autres ne le peuvent pas (et vice-versa), bien qu'il semble se comporter de la même manière dans d'autres cas. Je n'ai rien trouvé qui l'explique directement dans la documentation.

Réponses

8 trentcl Oct 10 2020 at 22:09

La réponse de prog-fh est essentiellement correcte, mais manque de nuances. Rust a trois types de types fonctionnels:

  1. Les éléments de fonction sont ce que vous obtenez lorsque vous créez une fonction à l'aide defn foo() {...}. C'est aussi le type du constructeur d'une structure de type tuple ou d'une variante enum. Les éléments de fonction sont de taille zéro (ils ne contiennent aucune donnée), et chaque fonction non générique a un type d'élément de fonction unique et innommable. Dans les messages d'erreur, le compilateur affiche ces "types Voldemort" comme quelque chose commefn() -> () {foo}(avec le nom de la fonction dans{}).

  2. Les fermetures sont des valeurs similaires aux éléments de fonction, mais les fermetures peuvent contenir des données: des copies ou des références à toutes les variables qu'elles capturent de leur environnement. Comme vous le savez déjà, vous créez une fermeture en utilisant la syntaxe de fermeture (|args| expression). Comme les éléments de fonction, les fermetures ont des types uniques et innommables (rendus par le compilateur à peu près[closure@src/main.rs:4:11: 4:23]).

  3. Les pointeurs de fonction sont ce que vous demandez: les types qui ressemblentfn() -> (). Les pointeurs de fonction ne peuvent pas contenir de données, mais ils ne sont pas de taille zéro; comme leur nom l'indique, ce sont des pointeurs. Un pointeur de fonction peut pointer vers un élément de fonction ou vers une fermeture qui ne capture rien, mais il ne peut pas être nul.

Les éléments de fonction et les fermetures sont automatiquement forcés au type de pointeur de fonction approprié lorsque cela est possible, c'est pourquoi cela let f: fn(i32) = |_| ();fonctionne: parce que la fermeture ne capture rien, elle peut être forcée à un pointeur de fonction.

Les trois types comme fonction de mettre en œuvre les pertinentes Fn, FnMutet les FnOncetraits (sauf que les fermetures pourraient ne pas mettre en œuvre Fnou en FnMutfonction de ce qu'ils capture). Éléments de fonction et des pointeurs de fonction mettent également en oeuvre Copy, Clone, Sendet Sync(fermetures à mettre en œuvre que ces traits quand tout leur contenu font).

En termes de performances, les pointeurs de fonction sont en quelque sorte un compromis entre les génériques et les objets de trait. Ils doivent être déréférencés pour être appelés, donc appeler un pointeur de fonction peut être plus lent que d'appeler un élément de fonction ou une fermeture directement, mais toujours plus rapide que d'appeler un dyn Fnobjet trait, qui implique une recherche de vtable en plus de l'appel indirect.

Références

  • Quelle est la différence pratique entre l'élément fn et le pointeur fn?
  • Pourquoi concevoir un langage avec des types anonymes uniques?
  • Comment créer une structure pour FFI qui contient un pointeur de fonction Nullable?
  • Pourquoi passer une fermeture à une fonction qui accepte un pointeur de fonction ne fonctionne pas?
3 prog-fh Oct 10 2020 at 21:07

C'est un type de pointeur de fonction .

Il se réfère uniquement à une fonction, pas à une fermeture, car il contient uniquement l'adresse de la fonction et non l'environnement capturé dont une fermeture a besoin.

Un Fntrait (F majuscule) peut désigner soit une fermeture, soit une fonction.

NickDecroos Oct 10 2020 at 21:07

fn est le type d'un pointeur de fonction. Voir aussi ici dans la documentation:https://doc.rust-lang.org/std/primitive.fn.html