Rust vs Golang
Published:
This blog compares Rust and Golang.
Similarities
Memory Safety
Historically, one of the biggest causes of software bugs and security vulnerabilities has been accessing memory unsafely or incorrectly.
Rust and Go deal with this problem in different ways, but both aim to be smarter and safer than other languages about managing memory.
Fast, Compact Executables
They’re both compiled languages, which means your programs are translated directly to executable machine code, so that you can deploy your program as a single binary file. This also makes both Rust and Go programs extremely fast in comparison to interpreted languages such as Python or Ruby.
General-Purpose Languages
Rust and Go are also both powerful, scalable general-purpose programming languages, which you can use to develop all kinds of modern software. Both have excellent standard libraries and a thriving third-party ecosystem, as well as great commercial support and a large user base.
Pragmatic Programming Style
While both Go and Rust have features associated with functional and object-oriented programming (OOP), they’re pragmatic languages aimed at solving problems in whatever way is most appropriate.
Development at Scale
Both Rust and Go have some useful features which make them suitable for programming in the large, whether that means large teams, or large codebases, or both.
For example, both Rust and Go use a standard code formatting tool (gofmt for Go, rustfmt for Rust), putting an end to useless arguments over where to put your brackets.
Both also have excellent, built-in, high-performance standard build and dependency management tools; no more wrestling with complex third-party build systems and having to learn a new one every couple of years.
Differences
Performance
Both Go and Rust are very fast. However, while Go’s design favors fast compilation, Rust is optimized for fast execution.
Rust’s run-time performance is also more consistent, because it doesn’t use garbage collection. On the other hand, Go’s garbage collector takes some of the burden off the programmer, making it easier to focus on solving the main problem, rather than the fine detail of memory management.
Rust is a better choice for areas where speed of execution beats all other considerations, such as game programming, operating system kernels, web browser components, and real-time control systems.
Simplicity
Go is a small language, by design: it has very little syntax, few keywords, and as few language constructs as it can get away with. You can learn the basics of Go and be productive in the language very quickly.
That gives Go the advantage in projects with a short timescale, or for teams that need to onboard lots of new programmers quickly, especially if they’re relatively inexperienced.
Features
At the other end of the scale, Rust has just about every feature you could imagine in a programming language, and some you probably can’t. That makes it a powerful and expressive language, with lots of different ways to do the same thing.
If you’re transitioning to Rust from some other language, you can probably find Rust equivalents for most of the features you’re used to. That gives Rust the advantage when large projects need to be migrated from a traditional language such as C++ or Java.
Concurrency
Unlike most languages, Go was designed with built-in features for concurrent programming, such as goroutines (a lightweight version of threads) and channels (safe and efficient ways to communicate data between concurrent tasks).
These make Go the perfect choice for high-scale concurrent applications such as webservers and microservices.
Safety
Rust is carefully designed to ensure that programmers can’t do something unsafe that they didn’t mean to do, such as overwriting a shared variable. The compiler requires you to be explicit about the way you share data between different parts of the program, and can detect many common mistakes and bugs.
As a result, so-called “fighting with the borrow checker” is a common complaint among new Rust programmers. Implementing your program in safe Rust code often means fundamentally re-thinking its design, which can be frustrating, but the benefits can be worth it when reliability is your top priority.
Scale
Go was designed to make it easy to scale both your projects and your development teams. Its minimalist design leads to a certain uniformity, and the existence of a well-defined standard style means that any Go programmer can read and understand a new codebase relatively quickly.
When it comes to software development in the large, clear is better than clever. Go is a good choice for big organizations, especially with many distributed teams. Its fast build times also favor rapid testing and deployment.
Trade-offs
Garbage Collection
Languages (like Go) that feature garbage collection, and automatic memory management in general, make it quick and easy to develop reliable, efficient programs, and for some people that’s the most important thing.
But garbage collection, with its performance overhead and stop-the-world pauses, can make programs behave unpredictably at run-time, and some people find this inconsistency unacceptable.
Languages (such as Rust) where the programmer must take explicit responsibility for allocating and freeing every byte of memory, are better for real-time or ultra-high-performance applications.
Error Handling
In some languages, when a function encounters an error (for example, something like “file not found”), it can be handled explicitly, or it can be automatically propagated back to the function’s caller, and the caller’s caller, and so on, until it either finds someone willing to handle the problem, or the program crashes with an ugly error message.
Errors that trigger an automatic return from the function if not handled are called exceptions, and, while convenient for programmers, can lead to some confusing behavior—especially if the exceptions are used deliberately as a control flow mechanism.
In both Rust and Go, while exceptions are available, their use is strongly discouraged. Instead, Go lets the programmer choose to either ignore a possible error, or explicitly check and return it (perhaps with some added context, via the error wrapping feature).
Rust’s error handling is even more powerful, relying on built-in Option
and Result
types which indicate that a return value may or may not be present, or may instead be some error. If a function returns Result
, for example, its return value can’t be used directly: Rust’s strict type system forces you to specify what should happen instead if there’s an error.
However, Rust also provides a neat syntactic shorthand: the ?
operator causes a function to return automatically if the Option
value is not present, or the Result
value contains an error. Since errors happen a lot, this gives Rust programmers a more compact way to write the necessary handling code than is available in Go.
Abstraction
The history of computer programming has been a story of increasingly sophisticated abstractions that let the programmer solve problems without worrying too much about how the underlying machine actually works.
That makes programs easier to write and perhaps more portable. But for many programs, access to the hardware, and precise control of how the program is executed, are more important.
Rust aims to let programmers get “closer to the metal”, with more control, but Go abstracts away the architectural details to let programmers get closer to the problem.
Speed
Rust makes a number of design trade-offs to achieve the best possible execution speed. By contrast, Go is more concerned with simplicity, and it’s willing to sacrifice some (run-time) performance for it.
Whether you favor Rust or Go on this point depends on whether you spend more time waiting for your program to build, or waiting for it to run.
Correctness
Go and Rust both aim to help you write correct programs, but in different ways: Go provides a superb built-in unit testing framework, for example, and a rich standard library, while Rust is focused on eliminating run-time bugs using its borrow checker.
It’s probably fair to say that it’s easier to write a given program in Go, but the result may be more likely to contain bugs than the Rust version. Rust imposes discipline on the programmer, but Go lets the programmer choose how disciplined they want to be about a particular project.