Why Rust: A Language Pursuing Zero-Cost Abstractions from a Go Perspective

🔊

This article is based on Rust 1.82 (released on 2026-01-23, current latest stable version). Rust is a modern systems programming language proven in production. Official documentation is at doc.rust-lang.org, and installation guide is at rust-lang.org/tools/install/.

Why Rust?

If you’ve already mastered Go, you might ask: why learn Rust? Rust exists to fill the performance and control gap that Go leaves open.

Go has conquered cloud-native and microservices domains with its extremely low learning curve, excellent concurrency model, and fast compilation speed. But its garbage collector (GC) and fixed runtime make it constrained in systems programming, embedded, and high-performance scenarios. When you need more precise memory control, lower latency, or work in embedded environments without OS kernel support, Go’s GC becomes a burden.

Rust targets performance and expressiveness close to C/C++, while guaranteeing memory safety at compile-time through the ownership system without introducing runtime overhead. This means you can write code with performance close to C while avoiding common memory safety issues in C.

Rust’s Design Philosophy

Below are Rust’s core design principles, each contrasting with Go.

Zero-Cost Abstractions. Rust’s slogan is “abstractions should not bring runtime overhead.” In Go, calling an interface{} requires runtime type assertions, while Rust’s trait mechanism is completely static at compile-time. You can write high-level code, but the compiler optimizes it to machine code performance-equivalent to hand-written low-level code. For developers used to Go’s “simplicity over complexity” philosophy, this requires understanding: Rust chooses to pay the price at compile-time in exchange for high runtime performance.

Memory Safety without Garbage Collection. Go manages memory automatically through GC, where developers only need to focus on business logic. Rust guarantees memory safety at compile-time through ownership, borrowing, and lifetime mechanisms. You don’t need to wait for GC pauses at runtime, but you need to think about memory lifetimes during coding. This trade-off makes Rust extremely attractive in embedded, real-time systems, and game development domains.

Fearless Concurrency. Go’s goroutine and channel make concurrency simple, but data races can still occur at runtime. Rust’s type system catches data races at compile-time—if your code compiles, you don’t need to worry about thread safety issues. This philosophy of “compile-time guarantees everything” is one of Rust’s most unique selling points.

High-Performance Toolchain. Go’s compiler is known for its speed, compiling large projects in just a few seconds. Rust’s compilation speed, while not as fast as Go, is acceptable on modern hardware through incremental compilation and parallel compilation. More importantly, Rust’s package manager Cargo provides a complete toolchain including dependency management, testing, and documentation generation, which is more integrated than Go’s go mod + manual scripts.

Go vs Rust Core Comparison

The following table helps you, familiar with Go, quickly locate Rust’s position in the technical spectrum:

FeatureGoRust
Memory ManagementGarbage Collection (GC)Ownership + Borrowing Check
RuntimeYes (goroutine scheduler, GC)No (zero-cost abstractions)
Error HandlingMultiple returns (error)Result<T, E> enum
GenericsYes (1.18+)Yes (trait + generic parameters)
Concurrencygoroutine + channelasync/await + std::thread
Compilation SpeedExtremely fastSlow (but incremental compilation acceptable)
Learning CurveGentleSteep

This table is not to rank, but to help you position: each language has its own design trade-offs. Rust chose the route of “catching errors at compile-time”—no GC means you need to understand the ownership system, no runtime means your program is the binary itself, and the Result type lets you know every point where a function might fail.

For developers transitioning from Go, the biggest mental shift is memory management: you need to understand concepts of ownership and borrowing, and explicitly express these intentions in your code. This sounds complex, but the Rust compiler provides extremely friendly error messages to help you understand the problem.

Use Cases

Rust is particularly suitable for the following scenarios:

  • Systems Programming: OS kernels, file systems, network protocol stacks
  • Embedded Development: Running on bare metal devices without OS
  • WebAssembly: Compile to WASM to run high-performance code in browsers
  • High-Performance Services: Backend services requiring low latency and high throughput
  • Game Development: Game engines, network synchronization, physics simulation

In comparison, Go is more suitable for:

  • Cloud-native infrastructure (Kubernetes, Docker)
  • Microservices and API services
  • Command-line tools and small utilities
  • Rapid prototyping and MVP development

Installing Rust

Rust’s official installation tool is rustup, which not only installs the Rust compiler rustc and package manager cargo, but also manages different Rust versions and target platforms.

Installing with rustup

On macOS and Linux, run:

bash
1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

On Windows, download and run rustup-init.exe.

During installation, rustup will ask for some configuration options. For first-time installation, choose the default options (just press Enter).

After installation, reload your shell configuration:

bash
1
source $HOME/.cargo/env

Verify installation:

bash
1
2
rustc --version
cargo --version

You should see output similar to:

1
2
rustc 1.82.0 (2026-01-23)
cargo 1.82.0

rustup toolchain management

Rustup allows you to easily switch between different versions of Rust toolchains. For example, install and use the latest nightly version:

bash
1
2
rustup install nightly
rustup default nightly

Or view all installed toolchains:

bash
1
rustup show

Note: For the learning stage, it’s recommended to use the stable toolchain (installed by default). The nightly version includes experimental features and may be unstable.

Configuring China mirror (optional)

If you’re in mainland China, downloading dependencies might be slow. You can configure a domestic mirror source. Add to ~/.cargo/config file:

toml
1
2
3
4
5
[source.crates-io]
replace-with = 'ustc'

[source.ustc]
registry = "sparse+https://mirrors.ustc.edu.cn/crates.io-index/"

Cargo Basics

Cargo is Rust’s package manager and build system. It integrates dependency management, compilation, testing, documentation generation, and other functions. Compared to Go’s go mod, Cargo provides a more complete development ecosystem.

Creating a new project

Use cargo new to create a new Rust project:

bash
1
2
cargo new hello_rust
cd hello_rust

This creates a standard Rust project structure:

1
2
3
4
hello_rust/
├── Cargo.toml      # Project configuration file
└── src/
    └── main.rs     # Source code file

Open Cargo.toml, and you’ll see content similar to:

toml
1
2
3
4
5
6
[package]
name = "hello_rust"
version = "0.1.0"
edition = "2021"

[dependencies]

Cargo.toml is similar to Go’s go.mod, but with richer functionality. You can define project metadata, dependency versions, workspace configurations, and more here.

Building and running

In the project directory, use the following commands:

bash
1
2
3
cargo build      # Compile project (debug mode)
cargo run        # Compile and run
cargo build --release  # Compile project (release mode, optimize performance)

When you run cargo build for the first time, Cargo will download and compile all dependencies. Subsequent builds will use incremental compilation, so it will be much faster.

Hello World

Open src/main.rs, and you’ll see Cargo has already generated a Hello World program for you:

rust
1
2
3
fn main() {
    println!("Hello, world!");
}

fn main() is the program’s entry point, similar to Go’s func main() { ... }. println! is a macro (note the ! at the end), which prints formatted strings to standard output.

Run the program:

bash
1
cargo run

You should see the output:

1
Hello, world!

Simple ownership concept preview

In Rust, ownership is one of the most core concepts. Here’s a simple example to give you a preview:

rust
1
2
3
4
5
6
7
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // Ownership transfers from s1 to s2

    // println!("{}", s1);  // Error! s1's ownership has been transferred, cannot use anymore
    println!("{}", s2);  // Correct
}

In Go, you can freely copy strings because Go’s strings are immutable value types, and copying only copies the underlying pointer and length. But in Rust, String is a mutable heap-allocated type, and it has ownership—only one owner at a time.

When you assign s1 to s2, s1’s ownership “moves” to s2, and s1 becomes invalid. This is Rust’s “move semantics,” which avoids memory double-free issues.

We’ll explain this concept in detail in later chapters. For now, just know: Rust guarantees memory safety at compile-time through this mechanism.

Summary and Next Post Preview

In this post, we understood Rust’s design philosophy from a Go perspective, its position in the systems programming spectrum, and installed the Rust toolchain. Key takeaways:

  • Rust fills the performance and control gap that Go (with GC and large runtime) has in systems programming and high-performance scenarios
  • Core design philosophy: zero-cost abstractions, memory safety without GC, fearless concurrency, high-performance toolchain
  • Memory management is implemented through the ownership system, the biggest adjustment for Go developers
  • rustup + Cargo provides a complete modern toolchain
  • The ownership system guarantees memory safety at compile-time, avoiding runtime GC overhead

The next post will dive into Rust’s basic syntax: variables, types, functions, and basic control flow, as well as core differences from Go. We’ll see how Rust lets you write safer code through its type system and compiler checks.


Series Contents (Six Posts):

  1. Why Rust: A Language Pursuing Zero-Cost Abstractions from a Go Perspective (This post)
  2. Basic Syntax: Quickly Learn Rust with Go Experience — Variable bindings, type inference, match expressions, Option
  3. Ownership and Borrowing: Rust’s Core Mechanism — Move semantics, borrow checker, lifetimes
  4. Error Handling: Result<T, E> and the ? Operator — Error handling patterns without panic
  5. Structs and Traits: Abstraction and Composition — impl blocks, trait objects, trait bounds
  6. Concurrency and Async: std::thread, async/await, and tokio — From goroutine to async runtimes