Je connais assez bien Go, pour avoir écrit un certain nombre de petits programmes. La rouille, bien sûr, je la connais moins bien, mais je garde un œil dessus.
Ayant récemment lu http://yager.io/programming/go.html , je pensais que j’examinerais personnellement les deux méthodes de traitement des génériques car cet article semblait critiquer injustement Go. En pratique, Interfaces n’était pas très efficace. ne pouvait pas accomplir élégamment. Je n'arrêtais pas d'entendre le battage médiatique sur la puissance des traits de Rust et sur les critiques de Go. Ayant de l'expérience dans Go, je me suis demandé à quel point c'était vrai et quelles étaient les différences. Ce que j'ai trouvé, c'est que les traits et les interfaces sont assez similaires! En fin de compte, je ne suis pas sûr d’avoir oublié quelque chose; voici donc un bref aperçu éducatif de leurs similitudes afin que vous puissiez me dire ce que j’ai manqué!
Voyons maintenant les interfaces Go de leur documentation :
Les interfaces dans Go fournissent un moyen de spécifier le comportement d'un objet: si quelque chose peut le faire, il peut être utilisé ici.
De loin, l'interface la plus commune est celle Stringer
qui renvoie une chaîne représentant l'objet.
type Stringer interface {
String() string
}
Donc, tout objet qui a String()
défini dessus est un Stringer
objet. Cela peut être utilisé dans des signatures de type telles que celles-ci func (s Stringer) print()
prennent presque tous les objets et les impriment.
Nous avons aussi interface{}
qui prend n'importe quel objet. Nous devons ensuite déterminer le type au moment de l'exécution par réflexion.
Jetons maintenant un coup d'œil à Rust Traits à partir de leur documentation :
Dans sa forme la plus simple, un trait est un ensemble de zéro ou plusieurs signatures de méthode. Par exemple, nous pourrions déclarer le trait Printable pour les éléments pouvant être imprimés sur la console, avec une signature de méthode unique:
trait Printable {
fn print(&self);
}
Cela ressemble immédiatement à nos interfaces Go. La seule différence que je vois est que nous définissons des «implémentations» de traits plutôt que de simplement définir des méthodes. Alors on fait
impl Printable for int {
fn print(&self) { println!("{}", *self) }
}
au lieu de
fn print(a: int) { ... }
Question bonus: que se passe-t-il dans Rust si vous définissez une fonction qui implémente un trait mais que vous n'utilisez pas impl
? Ça ne marche pas?
Contrairement aux interfaces de Go, le système de typage de Rust comporte des paramètres de type qui vous permettent de créer des génériques appropriés, par exemple interface{}
lorsque le compilateur et le moteur d'exécution connaissent réellement le type. Par exemple,
trait Seq<T> {
fn length(&self) -> uint;
}
fonctionne sur n’importe quel type et le compilateur sait que le type des éléments de séquence au moment de la compilation plutôt que d’utiliser la réflexion.
Maintenant, la vraie question: est-ce que je manque des différences ici? Sont - ils vraiment que la même? N'y a-t-il pas une différence plus fondamentale qui me manque ici? (En usage. Les détails de la mise en œuvre sont intéressants, mais finalement pas importants s'ils fonctionnent de la même manière.)
Outre les différences syntaxiques, les différences réelles que je vois sont les suivantes:
- Aller a envoi automatique de méthode contre Rust nécessite (?)
impl
S de mettre en œuvre un trait- Elégant vs Explicite
- La rouille a des paramètres de type qui permettent des génériques appropriés sans réflexion.
- Allez vraiment n'a pas de réponse ici. C’est la seule chose qui est nettement plus puissante et c’est au final juste un remplacement pour les méthodes de copier-coller avec des signatures de types différentes.
S'agit-il des seules différences non négligeables? Si tel est le cas, il semblerait que le système d'interface / type de Go n'est, dans la pratique, pas aussi faible qu'il est perçu.
AnyMap
est une bonne démonstration des forces de Rust, combinant des objets de trait avec des génériques pour fournir une abstraction sûre et expressive de la chose fragile qui serait nécessairement écrite dans Gomap[string]interface{}
.