Rust vs. Go – Ein Vergleich

Screenshot von Redox - ein Vergleich der Programmiersprachen Rust und Go

Sowohl Rust als auch Go sind relativ neue Sprachen. Go – auch bekannt als „Golang“ – wurde im Jahr 2007 bei Google in erster Linie für die Systemprogrammierung erstellt, um bestimmte Google-Probleme zu lösen. Rust war ein persönliches Projekt von Mozilla-Mitarbeiter Graydon Hoare. Es wurde dann 2009 von Mozilla gesponsert und ein Jahr später veröffentlicht. Rust ist im Vergleich zu Go eher eine Allzweck-Sprache. In diesem Artikel werde ich bestimmte Features auswählen, die beide gemeinsam haben, und dann erklären, wie sie sich unterscheiden.

 

Einfachheit oder Komplexität?

Im Gegensatz zu Rust zielt Go auf Einfachheit ab. Im Vergleich zu C++ (Go wurde entworfen, um C++ zu ersetzen) hat Go weit weniger Keywords – die Sprache ist übersichtlich und einfach. Rust ist komplexer als Go – die Sprache zielt darauf ab, eine bessere Version von C zu sein. Der Fokus liegt auf Sicherheit, Schnelligkeit und Parallelität.

Eines der Probleme, das Go lösen möchte, ist die Compiler-Ineffizienz in C und C++. Es wurde festgestellt, dass bei der Erstellung eines Programms mit 2.000 Dateien und insgesamt 4,2 MB das Compiler-Reading eine Größe von 8 GB hatte, wenn es verkettet wird. Das heißt, das Programm las effektiv jedes Byte in der Quelldatei 2.000 Mal – einfach aufgrund der Art und Weise, wie der Compiler arbeitet. Go vermeidet dies, indem es Pakete importiert; aber es nimmt das kompilierte Objekt und nicht die Quelle. Das Ergebnis ist eine sehr schnelle Kompilierung, wahrscheinlich schneller als in jeder anderen Programmiersprache. Es sollte hier erwähnt werden, dass Borland bereits vor 25 Jahren ein ähnliches System mit dem Borland Pascal Compiler benutzte.

 

Parallelität

Der Übergang zu Multi-Core, mit dem das zwangsläufige Scheitern des Mooreschen Gesetzes vermieden wird, hat den Programmierern ein neues Problem beschert. Ein Programm, das nur einen Kern auf einer CPU verwendet, die 8 oder 12 Kerne hat (mit Hyperthreading), ist natürlich erheblich unter-powered. Sowohl Rust als auch Go bieten eingebaute Parallelität, aber auf unterschiedliche Art und Weise.

Go hat folgende Philosophie: Kommuniziere nicht, indem du Speicherplatz teilst, sondern teile Speicherplatz durch Kommunikation. (Do not communicate by sharing memory; instead, share memory by communicating.) Es unterstützt Goroutines als Teil seiner CSP (Communicating Sequential Processes). Jede Goroutine ist ein Prozess, der unabhängig vom Hauptprozess läuft und sich so lange fortsetzt, bis er beendet wird, was in der Regel durch eine return-Anweisung geschieht. Sie starten eine Goroutine durch eine Funktion mit dem Wort “go”. Die Kommunikationskanäle sind „First-Class-Objekt“ – man kann sie deklarieren, sie also als Variablen durchgeben. Sie werden eingerichtet, um typisierte Daten zwischen Goroutines zu bewegen. Sie sind in Etwa so ähnlich wie eine UNIX Pipe.

Es gibt keine Beschränkungen dafür, wie Goroutines auf Shared Data zugreifen, was Race Conditions ermöglicht. Wenn ein Programm nicht über Kanäle oder andere Wege synchronisiert, dann können Writes von einer Goroutine für andere teilweise oder vollständig sichtbar oder aber komplett unsichtbar sein, oft ohne Garantie über das Ordering der Writes. Des Weiteren sind Go-interne Datenstrukturen wie Interface-Werte, Slice-Headers, Hash-Tabellen und String-Header nicht immun gegenüber Race Conditions. Deshalb kann die Typ- und Speicher-Sicherheit in Multithreaded-Programmen verletzt werden, die gemeinsam genutzte Instanzen dieser Typen ohne Synchronisation verändern.

Rust hat eine Thread Library (std::thread) und wurde designed, um Race Conditions zu verhindern. Dies kam zustande, weil Rust das Eigentum an Daten managed und durchsetzt. Für eine detailliertere Erklärung, wie Rust dies tut (sie wäre zu lang für diesen Artikel), siehe diesen Blog-Beitrag vom Rust-Team.

 

Typen

Go hat eine Vielzahl von Typen und kann Typen auf Basis von anderen erklären. Zum Beispiel:

   type T1 string
   type T2 T1
   
   var fred T1

 

Dennoch: Go ist nicht objektorientiert. Doch Sie können Methoden zu Typen hinzufügen (zum Beispiel auf einem Struct). Und Sie können Interface-Typen angeben, die durch jeden Typ implementiert sind, der die Methoden im Interface implementiert. Da fast jeder Typ Methoden haben kann, kann fast alles einem Interface gerecht werden.

Rust ist vielleicht etwas traditioneller und hat eine lange Typen-Liste. Allein für Integer gibt es i8, i16, i32, i64, u8, u16, u32, u64, isize, usize, f32 und f64. Man kann nur raten, was die meisten davon bedeuten. Die zwei Typen isize und usize hängen von der Größe eines Pointers der betreffenden Maschine ab. Außerdem gibt es str (String), Arrays, Tuples, Scheiben (slices) anderer Daten und Funktionen. (Ja, Funktionen haben einen Typ.)
Variablen sind unveränderlich, es sei denn sie werden mit dem Wort mut definiert.

let fred=5;
fred=7; // compiler says no
let mut dave = 4;
dave=8;

 

Veränderbare Referenzen!

let mut x = 10;  // Can change x later
let y = &mut x; 

 

Hier verweist y auf x und Sie können den Wert von x mit *y ändern. Sie können aber y nicht so ändern, dass es auf etwas anderes verweist.

*y= 8;  // dereferencing a reference. 

 

Rust hat drei Typen von Smart-Pointers. Es kann auf Raw Pointers zugreifen, was aber unsicher ist. Rust hat auch Generika in Form von parametrischem Polymorphismus. Stellen Sie sich einfach vor, Sie schreiben Funktionen wie Sort, die sich auf ints, floats etc. beziehen.

 

Garbage Collection

Go hat Garbage Collection. Es unterstützt Parallelität, indem es die Notwendigkeit der Kontrolle der Speicherverwaltung von Objekten zwischen Threads reduziert. Außerdem kann der Programmierer das Layout und die Zuordnung des Speichers kontrollieren. Dies kann verwendet werden, um den Overhead gering zu halten.

Rust hat keinen Garbage Collector, aber es verfolgt den Ownership von Objekten durch Variablen und ruft den Destructor, wenn die Variablen außerhalb des Gültigkeitsbereichs liegen. Rust erreicht Sicherheit durch Kontrolle über den Ownership, die es bei der Kompilierung durchführt. Siehe:

let v = vec![1, 2, 3];
let v2 = v;

 

Nach der zweiten Zeile kann man erneut v benutzen, um auf den Vektor mit 1, 2 und 3 zuzugreifen. Ownership geht an v2. Einige Typen wie i32 enthalten einen Copy Trait, also ist das Beispiel unten OK. Beide Beispiele stammen aus dem Rust Book.

let v = 1;
let v2 = v;

 

Fazit

Rust hat die Version 1.0 im Mai 2015 erreicht. Die Version 1.7 kam im März 2016 raus. Eine Unix wie Micro-Kernal Operating System Redox OS wurde vom Entwickler Jeremy Soller in Rust geschrieben und läuft auf echter Hardware. Das Projekt befindet sich in der Entwicklung und ist hier auf GitHub zu sehen.
Die Go-Version 1.6 kam im November 2015 raus. Es hat sowohl innerhalb als auch außerhalb von Google gute Ergebnisse erzielt – bei Google mit der Absicht, viele ältere Technologie-Projekte zu ersetzen. Es wird in Docker benutzt, um Linux Container einzusetzen; in Dropbox ersetzt es in einigen Fällen Python. Für eine längere Liste mit Notable Users siehe die Wikipedia-Seite für Go. Um sich ein genaueres Bild über die breiten Anwendungsmöglichkeiten von Go zu machen, gibt es bei Go Wiki auf GitHub eine lange Liste mit 14 Spielen!

Mein Eindruck ist, dass sich Go mit der früheren Einführung eine große Fangemeinde aufgebaut hat, aber Rust holt rasant auf. In den Reddit Programmierer-Gruppen haben beide große Communities: für Go mit 19.200 Nutzern, bei Rust sind es 14.700.

 

 

Weitere Themen:
4 Gründe, warum Hash Tables großartig sind
Diese IT-Firmen sind die Top Arbeitgeber in Deutschland
Die heißesten IT-Skills für 2016

About David Bolton

David Bolton begann schon mit dem Programmieren, als er noch zur Schule ging und bevor es überhaupt PCs gab. Es gefiel ihm so sehr, dass er seinen Abschluss in Informatik machte. Er beschäftigt sich seit fast 35 Jahren mit dem Thema Programmieren – sowohl arbeitsbedingt als auch in seiner Freizeit. In dieser Zeit arbeitete er für Price Waterhouse, British Aerospace, MicroProse (wo Sid Maier Civilization kreiert hat), in einer gescheiterten Dotcom (HomeDirectory.com) und bei Morgan Stanley. Mehr als acht Jahre lange programmierte er Spiele, mehr als 12 Jahre Finanz-Software in London. Sein Leben beschreibt er als eine permanente Lernkurve. Er verfügt über umfangreiche Programmiererfahrung in 6502,Z80 und 68000 Assembler, Basic, Pascal, C, C++, C#, Java, PHP, SQL, Fortran, JavaScript und lernt zurzeit R. Außerdem entwickelt er heute mobile Apps in Xamarin (C#) und schreibt für Dice. Er lebt in New York (in Lincolnshire, England, nicht in den USA).
No comments yet.

Leave a Reply