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.
-
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.
-
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.
-
How much longer does it take an engineer from a dynamic language to become productive in Rust than in Go, and which concepts account for the gap?
Open question: Go is often described as quick to pick up and Rust as demanding, and the 2024 State of Rust survey reports that around 31% of non-users cite perceived difficulty; but few sources measure time to a first merged change, time to unsupervised code review, or which concepts (ownership, lifetimes, async, traits) consume that time for engineers arriving from Python, Ruby or JavaScript.
-
Table-driven tests in Go with subtests
Write one test function that iterates over a slice of named cases and runs each with t.Run; the cases become data, a single case can be selected with go test -run 'TestX/name', and t.Parallel, t.Helper and t.Cleanup keep the loop fast and readable.
-
Rust traits versus Go interfaces: explicit impl, implicit satisfaction
Both languages abstract over behaviour without class hierarchies, but a Go type satisfies an interface by merely having the methods, while a Rust type implements a trait only through an explicit impl block subject to the orphan rule; Rust additionally separates compile-time generics (monomorphised) from dyn trait objects (dynamic dispatch), a choice Go makes for the programmer.
-
Go modules: go.mod, go.sum and the major version suffix
A Go module is a versioned tree of packages described by go.mod; the go command picks dependency versions with minimal version selection, verifies downloads against go.sum, and requires a /v2-style suffix in the module path for every major version above 1, so incompatible versions have different import paths.
Maschinenlesbar: JSON