Dans Rust, le principal outil d'abstraction est traits. En C++, il existe deux outils pour les abstractions: les classes abstraites et les modèles. Pour se débarrasser de certains des inconvénients de l'utilisation de modèles (par exemple, des messages d'erreur difficiles à lire), C++ a introduit concepts qui sont "ensembles nommés d'exigences" .
Les deux fonctionnalités semblent pour être assez similaires:
Mais d'après ce que je comprends, il existe également des différences notables. Par exemple, les concepts de C++ semblent définir un ensemble d'expressions qui doivent être valides au lieu de lister les signatures de fonction. Mais il y a beaucoup d'informations différentes et déroutantes (peut-être parce que les concepts ne se posent qu'en C++ 20?). C'est pourquoi j'aimerais savoir: quelles sont exactement les différences et les similitudes des concepts de C++ et des traits de Rust?
Y a-t-il des fonctionnalités qui ne sont offertes que par des concepts ou des traits? Par exemple. qu'en est-il des types et consts associés de Rust? Ou délimiter un type par plusieurs traits/concepts?
Avertissement: je n'ai pas encore utilisé de concepts, tout ce que je sais à leur sujet a été glané des différentes propositions et références, alors prenez cette réponse avec un grain de sel.
Les traits de rouille sont utilisés à la fois pour le polymorphisme à la compilation et, parfois, pour le polymorphisme à l'exécution; Les concepts ne concernent que le polymorphisme au moment de la compilation.
La plus grande différence entre les concepts et les traits est que les concepts utilisent typage structurel tandis que les traits utilisent typage nominal:
impl Trait for Type
est utilisé pour indiquer explicitement qu'un type implémente un trait.Il y a un certain nombre de conséquences; en général, le typage nominal est meilleur du point de vue de la maintenabilité - en ajoutant une exigence à un trait - tandis que le typage structurel vaut mieux un pontage de bibliothèques tierces - un type de la bibliothèque A peut satisfaire un concept de la bibliothèque B sans qu'ils soient conscients les uns des autres.
Les traits sont obligatoires:
Les concepts sont entièrement facultatifs:
Remarque: une contrainte est introduite par une clause requires
et spécifie des exigences ad hoc ou des exigences basées sur des concepts.
L'ensemble des exigences exprimables est différent:
La rouille n'a pas de concept de surcharge ad hoc, la surcharge ne se produit que par les traits et la spécialisation n'est pas encore possible.
Les contraintes C++ peuvent être utilisées pour "ordonner" les surcharges du moins spécifique au plus spécifique, afin que le compilateur puisse automatiquement sélectionner la surcharge la plus spécifique pour laquelle les exigences sont satisfaites.
Remarque: avant cela, SFINAE ou la répartition des balises seraient utilisées en C++ pour effectuer la sélection; la gymnastique était nécessaire pour travailler avec des ensembles de surcharge ouverts.
Comment utiliser cette fonctionnalité n'est pas encore très clair pour moi.
Les mécanismes d'exigence dans Rust sont purement additifs (conjonctions, aka &&
), en revanche, en C++ requires
, les clauses peuvent contenir des disjonctions (aka ||
).