Dans cet article, je vais tenter de comparer GoLang, Zig et Rust. Et pourquoi Rust gagne cette comparaison (pour moi).
J'ai écrit 3 de mes projets en GoLang, Zig & Rust. Ces projets sont suffisamment importants pour avoir une bonne idée des fondamentaux du langage, de ses lacunes et s'il y a un problème avec le langage, le framework ou l'écosystème.
CONSEIL : n'hésitez pas à accéder à la section TLDR pour obtenir la foutue réponse.
J'ai commencé à créer des outils de développement il y a quelques mois, d'abord avec GoLang.
Le premier était un utilitaire de base de gestion et de migration de bases de données (dbdaddy) et j'ai vraiment eu beaucoup de plaisir à travailler avec GoLang.
Même s'il s'agissait de ma toute première tentative avec GoLang pour créer quelque chose de plus sérieux que Advent Of Code et les problèmes de défi d'un milliard de lignes, J'ai été surpris qu'il m'ait fallu moins d'une semaine pour maîtriser ce domaine .
Pendant ce temps-là, je barbotais avec Zig à côté (rien de bien grave). J'ai entendu dire que Redis avait changé sa licence en une licence « techniquement non open source ».
Et je me suis dit : à quel point cela peut-il être difficile de créer un nouveau Redis open source en zig ?
Avance rapide 2 mois plus tard : merde.
L'idée de base derrière "GbCache" était un cache en mémoire basé sur LRU, mais la véritable source de vérité devait être enregistrée sur le disque avec des fonctionnalités telles que les notifications pour les changements de clé/valeur spécifiques provoqués et évidemment les TTL attribués aux clés.
Il est impressionnant de voir à quel point Zig est explicite, ce qui le rend d'autant plus simple et plus facile à utiliser.
J'ai démarré GbCache dans la perspective de « s'il devait passer à HyperScale™ demain, pourra-t-il gérer la charge ? »
Cette perspective m'a conduit à exclure GoLang car si je suis incapable de raisonner avec une extrême certitude sur les allocations de mémoire, je n'aurai pas un contrôle total sur la vitesse.
Faire les choses dans cette perspective est une très bonne expérience d'apprentissage car tout à coup, vous commencez à voir tous les points de votre programme qui pourraient exploser, manquer de mémoire ou devenir un goulot d'étranglement -les chemins chauds de votre code.
Grâce au caractère explicite de Zig, j'étais sûr de exactement où et quand j'allouais de la mémoire.
Mais... Zig n'est PAS un langage sans danger pour la mémoire en fin de compte et je suis un gars avec des problèmes de compétences de la taille de l'Everest.
entre dans la rouille
Au cours des 2 dernières années, j'ai essayé d'arrêter avec rage sur Rust 3 fois. Venant d'un environnement JavaScript où nous avons un milliard de Go de RAM dans nos macbook m69 max, je n'ai jamais vraiment compris pourquoi Rust avait ces règles, et se lancer dans le battage médiatique était probablement un mauvais angle de vue. .
Même si j'ai arrêté de fumer à plusieurs reprises, Rust était toujours dans un coin de mon esprit, avec sa syntaxe étrange, ses règles de mémoire frustrantes et ses durées de vie ahurissantes.
Mais quelque chose m'a frappé en écrivant Zig... Je gardais déjà une trace de toutes ces règles de mémoire et de toutes ces vies mais comme une surcharge mentale.
J'ai commencé à remarquer des modèles et des passe-partout dans mon code Zig en essayant de faire ce que Rust fait déjà.
Lors de la création du client CLI pour SFS (nom SFW - "Simple File Storage"), j'ai décidé de réessayer Rust.
Cette fois-ci, en parcourant le livre de rouille, j'ai commencé à ressentir le « pourquoi » de tout cela.
La chose la plus fondamentale que j'aime chez Rust est le modèle mental de la mémoire basé sur la propriété et l'emprunt.
Même si ce modèle de mémoire détenue et référencée est imaginaire, il s'agit d'un modèle mental pratique sur lequel raisonner et qui entraîne moins de surcharge au-dessus de ma tête.
Contrairement au modèle de mémoire mentale classique que des langages comme C & Zig infligent à votre tête. Devez-vous suivre les allocations de mémoire individuelles et leur durée de vie dans ma tête ? non merci !
Si vous êtes un ingénieur back-end normal au quotidien et que vous aimez faire des calculs sur leurs performances de sprint, votre meilleur choix est probablement GoLang.
"mais mon entreprise n'utilise pas GoLa—"
"quittez l'entreprise, quittez-la, utilisez le bon travail pour l'outil. quittez l'entreprise."
Pour moi, GoLang est comme un mariage arrangé où vous ne ressentez cette précipitation dans votre cœur mais il ne vous laisse jamais tomber, c'est votre compagnon de route ou de mort et vous pouvez parier toute votre vie dessus ça.
Mais mon ami, si vous cherchez ce rush, continuez à lire !
bu— mais je veux cette précipitation... je veux sentir mon cœur exploser en jetant un simple coup d'œil à leur syntaxe oculaire... je veux avoir l'impression d'être au paradis quand je suis avec eux et dans bon sang quand je ne le suis pas...
Jetons un coup d'œil rapide à un exemple de sécurité multithread dans Rust.
use std::thread; fn main() { let mut counter = Box::new(0); // 32-bit integer allocated on the heap let mut handles = vec![]; for _ in 0..10 { let handle = thread::spawn(|| { *counter += 1; // trying to edit the value }); handles.push(handle); } for handle in handles { handle.join().unwrap(); // WAITING FOR ALL THE THREADS TO COMPLETE } println!("Result: {}", *counter); }
Nous avons une valeur allouée au tas et 10 threads tentent de la modifier indépendamment.
Ce code accède de manière dangereuse à la variable compteur car tous les threads tenteront de modifier le compteur simultanément.
Dans d'autres langages, un code similaire sera volontiers compilé et exécuté.
Si vous avez déjà travaillé dans un environnement multithread, votre première pensée pourrait être d'utiliser un "mutex" pour éviter les conditions de concurrence lors de la mise à jour de la variable compteur.
Mais il est facile de manquer de petites choses comme celle-ci dans une grande base de code à cause d'une erreur humaine.
Rust ne laissera même pas ce programme se compiler.
En raison des règles de propriété et d'emprunt, le compilateur détectera que vous empruntez un compteur de manière mutable dans le premier thread de la première itération de la boucle for... ok jusqu'à maintenant... la deuxième itération veut aussi emprunter de manière mutable en parallèle ? dangereux ! déclenche une ERREUR DE TEMPS DE COMPILATION!!.
Référencer ou « emprunter » une valeur à son propriétaire avec l'intention de muter/modifier est appelé un « emprunt mutable »
use std::thread; fn main() { let mut counter = Box::new(0); // 32-bit integer allocated on the heap let mut handles = vec![]; for _ in 0..10 { let handle = thread::spawn(|| { *counter += 1; // trying to edit the value }); handles.push(handle); } for handle in handles { handle.join().unwrap(); // WAITING FOR ALL THE THREADS TO COMPLETE } println!("Result: {}", *counter); }
Dans des situations comme celles-ci, les autres langues ne vous donnent aucune erreur. Il est de votre responsabilité d'inspecter l'exactitude, Rust l'empêche.
Des constructions comme celles-ci réparties dans toute la langue vous aident à ne pas vous tirer une balle dans le pied (souvent).
ÇA DÉPEND !
J'aurais vraiment aimé qu'il y ait un langage qui soit la réponse et même si GoLang s'en rapproche assez, cela dépend vraiment de votre cas d'utilisation et, surtout, de votre équipe.
pour moi, Rust est un plaisir de travailler avec (pour l'instant, qui sait... hehe)
les gens de TigerBeetle ont tenté leur chance avec Zig et ils en sont satisfaits.
Primeagen est plus heureux avec Zig.
pour Jarred Sumner, Zig c'est bien, il a écrit Bun en Zig.
Mitchell Hashimoto (le gars derrière HashiCorp) écrit ghostty dans Zig, un terme BLAZING FAST—
.
.
.
attends...
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!