Fundamentals 32 min read

Master Rust Quickly: 30‑Line Greplite Demo & Core Concepts Explained

This comprehensive guide introduces Rust’s core syntax and unique programming mindset, walks through a practical greplite example, and covers essential topics such as installation, Cargo commands, data structures, ownership, traits, iterators, async/await, concurrency, and best learning resources for rapid mastery.

Tencent Technical Engineering
Tencent Technical Engineering
Tencent Technical Engineering
Master Rust Quickly: 30‑Line Greplite Demo & Core Concepts Explained

Introduction

Rust has been gaining industry adoption in recent years, appearing in Windows kernel components, Linux kernel, Chromium, AWS S3, and Azure. The growing Google Trends interest makes now an ideal time to start learning Rust.

1. Basics

1.1 Installing Rust and Using Cargo

Install Rust via the official installer https://www.rust-lang.org/tools/install . In China, use the mirror https://rsproxy.cn/ for faster downloads.

Common Cargo commands:

cargo build
cargo build --release
cargo clippy
cargo run 
cargo run -- --
cargo clean
cargo check
cargo doc
cargo expand # requires cargo install cargo-expand

Develop with VSCode + rust-analyzer.

1.2 greplite Mini‑Program

Create a binary crate and add the following code to main.rs:

use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn main() -> io::Result<()> {
    let args: Vec<_> = env::args().collect();
    if args.len() < 3 {
        eprintln!("Usage: greplite <search_string> <file_path>");
        std::process::exit(1);
    }
    let search_string = &args[1];
    let file_path = &args[2];
    run(search_string, file_path)
}

fn run(search_string: &str, file_path: &str) -> io::Result<()> {
    let file = File::open(file_path)?;
    let reader = BufReader::new(file);
    for line in reader.lines() {
        let line = line?;
        if line.contains(search_string) {
            println!("{line}");
        }
    }
    Ok(())
}

Run with cargo run -- main src/main.rs. The program demonstrates Rust’s use of use, fn, the Result type, error propagation with ?, and iterator‑based file processing.

1.3 Organizing Data

Rust provides three primary ways to structure data:

Structs for named fields.

Tuples for ordered, unnamed values.

Enums for variant types, often used with match.

struct Person {
    first_name: String,
    last_name: String,
    age: i32,
}

let person_info = ("Harry", "Potter", 18);
let (first_name, _, _) = person_info;

enum WebEvent {
    PageLoad,
    KeyPress(char),
    Click { x: i32, y: i32 },
    Paste(String),
}

1.4 Ownership

Ownership rules:

Every value has a single owner.

Only one owner exists at a time.

When the owner goes out of scope, the value is dropped.

Move semantics vs. copy semantics are illustrated with vec! and primitive types.

1.5 References and Borrowing

Rust enforces at any time either one mutable reference or any number of immutable references, and all references must be valid.

fn main() {
    let mut v = vec![1, 2, 3, 4];
    let first = &v[0];
    v.push(5); // error: cannot borrow `v` as mutable because it is also borrowed as immutable
    println!("first element: {}", first);
}

1.6 Traits

Traits define shared behavior. Example:

trait Shape {
    fn area(&self) -> f64;
}

struct Circle { radius: f64 }
impl Shape for Circle {
    fn area(&self) -> f64 { std::f64::consts::PI * self.radius * self.radius }
}

struct Rectangle { width: f64, height: f64 }
impl Shape for Rectangle {
    fn area(&self) -> f64 { self.width * self.height }
}

Traits enable static and dynamic dispatch via generics, impl Trait, and dyn Trait.

1.7 Iterators

Iterators are defined by the Iterator trait with a required next method. They are lazy, can be infinite, and have zero‑cost abstractions.

struct Fibonacci { current: u64, next: u64 }
impl Iterator for Fibonacci {
    type Item = u64;
    fn next(&mut self) -> Option<Self::Item> {
        let next_number = self.current + self.next;
        self.current = self.next;
        self.next = next_number;
        Some(self.current)
    }
}

for n in Fibonacci::new().take(10) {
    println!("{}", n);
}

1.8 Closures

Closures capture their environment and implement Fn, FnMut, or FnOnce depending on how they capture values.

let s = String::from("hello");
let f1 = || &s; // implements Fn
let mut s2 = String::from("hello");
let mut f2 = || s2 += "world"; // implements FnMut
let f3 = || s2; // implements FnOnce

1.9 Sync & Send

Concurrency safety is expressed via the Sync and Send traits. Examples using Arc, Mutex, and thread spawning demonstrate safe sharing across threads.

use std::sync::{Arc, Mutex};
use std::thread;
let data = Arc::new(Mutex::new(vec![1, 2, 3]));
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
    let mut guard = data_clone.lock().unwrap();
    guard.push(4);
});
handle.join().unwrap();
println!("{:?}", data.lock().unwrap());

1.10 Async & Await

Async functions compile to state machines implementing the Future trait. The await operator repeatedly polls the future until it is ready.

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let res = reqwest::get("https://geek-jokes.sameerkumar.website/api?format=json").await?;
    let joke: serde_json::Value = res.json().await?;
    println!("{}", joke["joke"]);
    Ok(())
}

2. Thinking in Rust

Rust emphasizes expressions as values, pattern matching beyond enums, powerful macros, message‑passing concurrency, and a memory model compatible with C++.

2.1 Expressions

Expressions can be assigned or returned directly, e.g., let x = if cond { 1 } else { 2 };.

2.2 Split Operations

Data structures like Vec and sockets can be split into independent parts for safe concurrent use.

2.3 Option & Result

Use ?, is_ok, let else, and iterator adapters to handle these enums concisely.

2.4 Match Beyond Enums

Match can be used with any value and must be exhaustive, providing powerful control flow.

2.5 Macros

Macros range from simple println! to attribute macros like #[tokio::main] and derive macros such as #[derive(Debug)].

2.6 Message‑Passing Concurrency

Channels enable pipelines where a producer lists objects and workers copy them, similar to Go’s model.

2.7 Memory Model

Rust shares C++‑style atomic operations; crates like aarc provide safe reclamation.

2.8 Interior Mutability

Patterns like RefCell and Mutex allow mutation through shared references.

2.9 Build Scripts

build.rs

runs at compile time for tasks such as embedding Git metadata or compiling C/C++ code.

2.10 Iterators Revisited

Iterators simplify many tasks; examples show using try_for_each and collection adapters.

2.11 Global Variables

Modern Rust provides OnceLock and LazyLock for safe global initialization without external crates.

3. Practical Project

Implement a mini‑Redis server following the GitHub repository . The project demonstrates networking, async I/O, and command parsing in Rust.

Learning Recommendations

Read "The Book" (official Rust book) thoroughly.

Complete all exercises on rustlings .

Avoid implementing linked lists as a learning exercise.

References

Using lightweight formal methods to validate a key‑value storage node in Amazon S3

https://rsproxy.cn/

The Rust Programming Language

This Week in Rust

Rustonomicon

Rust Reference

Rust Atomics and Locks

rustlings

Rust by Example

Rust 24‑Hour Crash Course

concurrencyRustprogrammingtutorialAsyncOwnershipTraits
Tencent Technical Engineering
Written by

Tencent Technical Engineering

Official account of Tencent Technology. A platform for publishing and analyzing Tencent's technological innovations and cutting-edge developments.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.