L'intervention récente de Dave Herman dans Rust dit qu'ils ont emprunté cette propriété à C++. Je n'ai rien trouvé sur ce sujet. Quelqu'un peut-il m'expliquer ce que signifie la monomorphisation ?
Réponses
Trop de publicités?La monomorphisation consiste à générer des versions spécialisées de fonctions génériques. Si j'écris une fonction qui extrait le premier élément de n'importe quelle paire :
fn first<A, B>(pair: (A, B)) -> A {
let (a, b) = pair;
return a;
}
et ensuite j'appelle cette fonction deux fois :
first((1, 2));
first(("a", "b"));
Le compilateur va générer deux versions de first()
l'un spécialisé dans les paires d'entiers et l'autre dans les paires de chaînes de caractères.
Le nom dérive du terme "polymorphisme" du langage de programmation, qui signifie qu'une fonction peut traiter plusieurs types de données. La monomorphisation est la conversion d'un code polymorphe en code monomorphe.
Je ne sais pas si quelqu'un s'intéresse encore à cette question, mais la documentation de Rust mentionne effectivement la manière dont elle réalise une abstraction sans coût grâce à ce processus. À partir de Performance du code en utilisant des génériques :
Vous vous demandez peut-être l'utilisation de paramètres de type générique. La bonne nouvelle est que Rust implémente les paramètres de type génériques de telle sorte que votre code ne s'exécute pas plus lentement en utilisant les types génériques qu'avec des types concrets.
Rust accomplit cela en effectuant utilise des génériques au moment de la compilation. La monomorphisation est le processus qui consiste à transformer du code générique en code spécifique en remplissant les types concrets qui sont utilisés lors de la compilation.
Au cours de ce processus, le compilateur fait l'inverse de ce que fait le pour créer la fonction générique dans le Listing 10-5 : le compilateur examine tous les endroits où le code générique est appelé et génère du code pour les types concrets. types concrets avec lesquels le code générique est appelé.
Voyons comment cela fonctionne avec un exemple qui utilise la norme de la bibliothèque standard :
let integer = Some(5); let float = Some(5.0);
Lorsque Rust compile ce code, il effectue une monomorphisation. Pendant ce processus, le compilateur lit les valeurs utilisées dans les instances de [ ] et l'autre est f64. En tant que tel, il étend la définition générique de Option en Option_i32 et Option_f64, remplaçant ainsi la définition générique de l la définition générique par les définitions spécifiques.
La version monomorphisée du code ressemble à ce qui suit. Le site générique est remplacée par les définitions spécifiques créées par le compilateur. le compilateur :
// Filename: src/main.rs enum Option_i32 { Some(i32), None, } enum Option_f64 { Some(f64), None, } fn main() { let integer = Option_i32::Some(5); let float = Option_f64::Some(5.0); }
Parce que Rust compile le code générique en code qui spécifie le type dans chaque instance, nous ne payons aucun coût d'exécution pour l'utilisation des génériques. Lorsque le code code s'exécute, il fonctionne exactement comme si nous avions dupliqué chaque définition à la main. Le processus de monomorphisation rend le code Rust génériques de Rust extrêmement efficaces à l'exécution.
Je n'en suis pas sûr ; pourriez-vous indiquer le lien vers la conférence ? Il pourrait s'agir d'une remarque désinvolte.
Herman a peut-être inventé un terme pour désigner quelque chose comme la spécialisation de modèle, qui génère des types/objets qui ne sont pas mutuellement liés (non polymorphes ou "monomorphes") à partir du modèle, qui est une structure polymorphe.
Il y a une belle explication de la monomorphisation dans le Livre de la rouille
La monomorphisation est le processus qui consiste à transformer du code générique en code spécifique en remplissant les types concrets qui sont utilisés lors de la compilation.
Dans l'exemple du livre, si vous avez défini des variables avec Some
:
let integer = Some(5); let float = Some(5.0);
Lorsque Rust compile ce code, il effectue une monomorphisation. Pendant ce processus, le compilateur lit les valeurs qui ont été utilisées en
Option<T>
et identifie deux types deOption<T>
: on esti32
a estf64
. En tant que telle, elle élargit la définition générique de laOption<T>
iOption_i32
yOption_f64
remplaçant ainsi le celles qui sont spécifiques.La version monomorphisée du code ressemble à ce qui suit. [ ]
Option<T>
est remplacé par les définitions spécifiques créées par le compilateur :Nom de fichier : src/main.rs
enum Option_i32 { Some(i32), None, } enum Option_f64 { Some(f64), None, } fn main() { let integer = Option_i32::Some(5); let float = Option_f64::Some(5.0); }