Thema: go
-
Go oder Rust für einen neuen Dienst wählen: ein Entscheidungsverfahren ohne Benchmarks
Die Wahl zwischen Go und Rust für einen Dienst anhand dokumentierter Spracheigenschaften und Teambeschränkungen treffen statt anhand von Benchmark-Folklore: Speicherverwaltungsmodell, Fehler- und Nebenläufigkeitsstil, Form der Arbeitslast, die Bibliotheken, mit denen der Dienst sprechen muss, und wer ihn in zwei Jahren pflegen wird.
-
Abbruch und Fristen in Go mit context.Context
Einen context.Context von der eingehenden Anfrage durch jeden Aufruf reichen, der blockieren kann, mit WithTimeout oder WithCancel abgeleitete Kindkontexte erzeugen, die Cancel-Funktion immer aufrufen und in Schleifen ctx.Done() prüfen, damit ein Verbindungsabbruch des Clients oder eine Frist den gesamten Baum von Goroutinen stoppt, statt sie weiterlaufen zu lassen.
-
Verstrichene Zeit in Go: Serialisierung verliert die monotone Uhrkomponente
Hält lokale Dauermessung getrennt von persistierten Zeitstempeln und prozessübergreifenden Fristenstrategien.
-
Go-Interfaces: implizite Erfüllung und das nicht-nil nil
Ein Go-Typ erfüllt ein Interface dadurch, dass er dessen Methoden besitzt; nichts wird deklariert. Das macht kleine Interfaces am Verwendungsort günstig, doch ein Interface-Wert ist ein Paar aus Typ und Wert, sodass ein nil-Pointer, der in einem error-Interface steckt, nicht gleich nil ist.
-
Go-append-Aliasing: sowohl den Pfad mit freier Kapazität als auch den Neuallokationspfad testen
Slice-Besitz explizit machen, wenn das Anhängen an eine Ansicht Speicher verändern kann, der anderswo beobachtet wird.
-
Fehlerbehandlung in Go: Wrapping mit %w, errors.Is und errors.As
Go-Funktionen geben Fehler als gewöhnliche Werte zurück; mit fmt.Errorf und dem %w-Verb wird Kontext hinzugefügt, sodass der ursprüngliche Fehler erreichbar bleibt, und die Kette wird dann mit errors.Is für Sentinel-Werte und errors.As (oder dem generischen errors.AsType) für Typen geprüft, statt Strings zu vergleichen oder == zu verwenden.
-
Goroutinen, Channels und das sync-Package: Nebenläufigkeit in Go im Überblick
Eine go-Anweisung führt einen Funktionsaufruf nebenläufig auf einem günstigen, wachsenden Stack aus; Channels übertragen Werte zwischen Goroutinen und blockieren, bis beide Seiten bereit sind; sync.WaitGroup, Mutex und Once decken die Fälle ab, in denen das Teilen von Speicher einfacher ist. Ein Data Race ist ein Fehler, dessen Ausgang das Memory Model nur teilweise einschränkt, und der -race-Detektor ist das Werkzeug, um ihn zu finden.
-
Wie viel länger braucht eine Fachperson aus einer dynamisch typisierten Sprache, um in Rust produktiv zu werden, als in Go, und welche Konzepte erklären diesen Unterschied?
Offene Frage: Go gilt oft als schnell erlernbar und Rust als anspruchsvoll, und die State-of-Rust-Umfrage 2024 berichtet, dass rund 31 % der Nichtnutzenden die wahrgenommene Schwierigkeit als Grund nennen; aber nur wenige Quellen messen die Zeit bis zur ersten gemergten Änderung, die Zeit bis zu unbeaufsichtigten Code-Reviews oder welche Konzepte (Ownership, Lifetimes, Async, Traits) diese Zeit für Fachleute beanspruchen, die von Python, Ruby oder JavaScript kommen.
-
Tabellengetriebene Tests in Go mit Subtests
Eine Testfunktion schreiben, die über ein Slice benannter Fälle iteriert und jeden mit t.Run ausführt; die Fälle werden zu Daten, ein einzelner Fall lässt sich mit go test -run 'TestX/name' auswählen, und t.Parallel, t.Helper und t.Cleanup halten die Schleife schnell und lesbar.
-
Go-Race-Detector-Abdeckung: ein sauberer Lauf sagt nichts über unausgeführte Pfade aus
Die Ergebnisse von go test -race mit den tatsächlich durchlaufenen nebenläufigen Pfaden verknüpfen, einschliesslich Start und Beendigung.
-
Rust-Traits versus Go-Interfaces: explizites impl, implizite Erfüllung
Beide Sprachen abstrahieren Verhalten ohne Klassenhierarchien, doch ein Go-Typ erfüllt ein Interface allein dadurch, dass er die Methoden besitzt, während ein Rust-Typ einen Trait nur über einen expliziten impl-Block implementiert, der der Waisenregel (orphan rule) unterliegt; Rust trennt zusätzlich zur Kompilierzeit erzeugte Generics (monomorphisiert) von dyn-Trait-Objekten (dynamischer Dispatch) – eine Entscheidung, die Go dem Programmierer abnimmt.
-
Go-Module: go.mod, go.sum und das Hauptversions-Suffix
Ein Go-Modul ist ein versionierter Baum von Paketen, beschrieben durch go.mod; der go-Befehl wählt Abhängigkeitsversionen per Minimal Version Selection, prüft Downloads gegen go.sum, und verlangt für jede Hauptversion über 1 ein Suffix nach dem Muster /v2 im Modulpfad, damit inkompatible Versionen unterschiedliche Importpfade haben.
-
Kopieren von Go-Mutexen: die Identität des Locks beim geschützten Zustand belassen
Value-Receiver, Zuweisungen und Container-Operationen überprüfen, die eine Struktur mit einem aktiven Mutex kopieren können.
Maschinenlesbar: JSON