How to Code in Rust: A Beginner's Guide to Ownership, Async, and CLI Tools

2026-06-05·Advanced Guides

Key Takeaways

  • Rust's ownership model eliminates memory bugs without a garbage collector, making it ideal for systems programming.
  • Async/await in Rust enables high-performance I/O with minimal overhead, using zero-cost abstractions.
  • Building CLI tools with Rust is straightforward thanks to crates like `clap` and `structopt`.
  • Systems programming in Rust gives you control over memory and performance, similar to C++, but with safety guarantees.

---

Introduction

Rust is not just another programming language. It's a language that promises memory safety without a garbage collector, and it delivers. I've been writing Rust for three years, and the learning curve is real—but worth it. This guide walks you through the core concepts: ownership, async/await, building CLI tools, and systems programming. Let's start with the most intimidating part.

Ownership: The Foundation

Ownership is Rust's superpower. Every value in Rust has a single owner at any time. When the owner goes out of scope, the value is dropped. This is how Rust manages memory without garbage collection.

```rust

fn main() {

let s = String::from("hello"); // s owns the string

takes_ownership(s); // ownership moves to the function

// println!("{}", s); // This would cause a compile error

}

fn takes_ownership(some_string: String) {

println!("{}", some_string);

} // some_string goes out of scope and memory is freed

```

Borrowing lets you reference data without taking ownership. Use `&` for immutable references and `&mut` for mutable ones. This prevents data races at compile time.

```rust

fn main() {

let mut s = String::from("hello");

let r1 = &s; // immutable borrow

let r2 = &mut s; // mutable borrow - this won't compile if r1 is still in use

r2.push_str(", world");

println!("{}", s);

}

```

Rule to remember: You can have either one mutable reference or any number of immutable references, but not both at the same time.

Async/Await: Handling I/O Efficiently

Rust's async model is based on zero-cost futures. Unlike other languages where async has significant overhead, Rust lets you write asynchronous code that's as fast as synchronous code.

Here's a simple async function that fetches a webpage:

```rust

use reqwest;

async fn fetch_url(url: &str) -> Result {

let response = reqwest::get(url).await?;

let body = response.text().await?;

Ok(body)

}

#[tokio::main]

async fn main() {

match fetch_url("https://example.com").await {

Ok(body) => println!("Fetched {} bytes", body.len()),

Err(e) => eprintln!("Error: {}", e),

}

}

```

Notice the `#[tokio::main]` macro. Tokio is the most popular async runtime for Rust, handling task scheduling and I/O. For smaller projects, you can use `async-std` instead.

Comparison table: Tokio vs async-std

FeatureTokioasync-std

---------------------------
PopularityMost widely used (~80% of async Rust projects)Smaller but growing
Runtime modelWork-stealing schedulerSingle-threaded or multi-threaded
Key strengthsHigh performance, extensive ecosystemSimpler API, similar to std
Learning curveSteeper due to advanced featuresGentler

Building CLI Tools

Rust is perfect for CLI tools because of its speed, safety, and cross-compilation capabilities. The `clap` crate makes argument parsing a breeze.

Here's a simple CLI tool that echoes input:

```rust

use clap::Parser;

#[derive(Parser)]

struct Args {

#[arg(short, long)]

name: String,

#[arg(short, long, default_value_t = 1)]

count: u32,

}

fn main() {

let args = Args::parse();

for _ in 0..args.count {

println!("Hello, {}!", args.name);

}

}

```

Compile with `cargo build --release`, and you get a single binary that runs on any machine without dependencies. I've used this approach to build tools that replace bash scripts in production—Rust binaries are typically 10-50x faster than equivalent Python or Node.js scripts.

Systems Programming: Raw Power with Safety

Systems programming in Rust means working with raw memory, hardware, and operating system interfaces. Rust gives you the control of C++ without the segfaults.

Here's an example of writing to a file using low-level system calls:

```rust

use std::fs::File;

use std::io::Write;

fn main() -> std::io::Result<()> {

let mut file = File::create("data.txt")?;

file.write_all(b"Hello, systems programming!")?;

Ok(())

}

```

For more advanced cases, like interacting with hardware, Rust's `unsafe` keyword lets you perform operations like dereferencing raw pointers or calling foreign functions. But use `unsafe` sparingly—I've found that 99% of systems programming can be done safely.

Common Pitfalls and How to Avoid Them

1. Fighting the borrow checker: If the borrow checker rejects your code, it's usually trying to prevent a bug. Instead of reaching for `unsafe`, refactor your code. Often, introducing a helper function or using a different data structure solves the issue.

2. Ignoring error handling: Rust's `Result` type forces you to handle errors. Use `?` to propagate errors, and consider using `anyhow` or `thiserror` for larger projects.

3. Overcomplicating async: Not every function needs to be async. For CPU-bound tasks, use synchronous code with threads. Async shines only for I/O-bound operations.

FAQ

Q: Is Rust harder to learn than C++?

A: Yes, initially. The borrow checker has a steep learning curve, but after a few months, you'll find Rust's rules prevent entire classes of bugs that plague C++ projects. The compiler errors are also much more helpful than C++'s cryptic messages.

Q: Can I use Rust for web development?

A: Absolutely. Frameworks like Actix-web and Rocket are production-ready. Companies like Dropbox and Figma use Rust for backend services. The async model is particularly good for handling thousands of concurrent connections.

Q: What's the best way to start learning Rust?

A: Read "The Rust Programming Language" book (free online) and work through the exercises. Then build a small CLI tool—something like a file renamer or a simple HTTP server. Real projects solidify concepts faster than tutorials.