Rust 07. Modules, Smart Pointers, Concurrency, and Async
Summary
Once you move past individual Rust syntax rules, the bigger questions become how to organize code, how to share values safely, and how to handle more than one task at a time. That is where module, smart pointers, concurrency, and async start to matter.
This post connects those four topics at a beginner-friendly level. In short, modules structure code, smart pointers refine ownership and access patterns, concurrency covers threads and shared-state coordination, and async focuses on efficiently scheduling wait-heavy work.
Document Information
- Written on: 2026-04-14
- Verification date: 2026-04-16
- Document type: tutorial
- Test environment: Windows 11 Pro, Cargo project, Windows PowerShell example commands,
src/main.rs - Test version: rustc 1.94.0, cargo 1.94.0
- Source quality: only official documentation is used.
- Note: the
module,Box,Rc,RefCell, channel, andArc<Mutex<_>>examples were rerun locally. Async examples that require a Tokio-style runtime were not rerun in this verification pass; instead, the post now states their execution requirements and source basis explicitly.
Problem Definition
At this stage of learning Rust, the following questions are easier to understand when treated as one connected set.
- how to split a growing codebase into files and modules
- how to model ownership when plain references are not enough
- how to coordinate threads through communication or shared state
- how to distinguish thread-based concurrency from runtime-based async execution
This post answers those questions at the beginner level. It does not cover production async runtime setup, custom executors, lock-free structures, or actor-style architectures.
Verified Facts
- Modules use
mod,pub, and paths to structure code and control visibility. Evidence: Managing Growing Projects with Packages, Crates, and Modules Box<T>,Rc<T>, andRefCell<T>are representative smart-pointer tools for heap allocation, single-thread shared ownership, and interior mutability. Evidence: Smart Pointers, [Using Boxto Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html), [Rc , the Reference Counted Smart Pointer](https://doc.rust-lang.org/book/ch15-04-rc.html), [RefCell and the Interior Mutability Pattern](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html) - Rust supports threads, message passing, and shared-state concurrency at the standard-library level, while using the type system to reduce unsafe sharing patterns. Evidence: Fearless Concurrency
- Async and await are built around futures and runtimes, and they are especially useful for wait-heavy workloads such as I/O. Evidence: Asynchronous Programming in Rust
- The simplest beginner practice flow still starts from a
cargo newproject. Evidence: Hello, Cargo!
Directly Confirmed Results
1. A fresh Cargo project made the standard-library examples easy to rerun
- Direct result: creating a small Cargo project and replacing
src/main.rswhile rerunningcargo runwas the simplest practice loop.
cargo new rust-modules-concurrency
cd rust-modules-concurrency
code .
cargo run
2. Modules and smart pointers exposed different ownership models clearly
- Direct result: the example below showed module access,
Box<T>,Rc<T>, andRefCell<T>in one place.
use std::cell::RefCell;
use std::rc::Rc;
mod greeting {
pub fn say_hello() {
println!("hello from module");
}
}
fn main() {
greeting::say_hello();
let number = Box::new(100);
println!("boxed = {}", number);
let name = Rc::new(String::from("rust"));
let a = Rc::clone(&name);
let b = Rc::clone(&name);
println!("rc count = {}", Rc::strong_count(&name));
println!("a = {}, b = {}", a, b);
let value = RefCell::new(10);
*value.borrow_mut() += 5;
println!("refcell = {}", value.borrow());
}
- Observed result:
hello from module
boxed = 100
rc count = 3
a = rust, b = rust
refcell = 15
3. Concurrency examples showed communication and shared state as different patterns
- Direct result: the example below reproduced both message passing through a channel and shared-state updates through
Arc<Mutex<_>>.
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(String::from("hello from thread")).unwrap();
});
println!("received = {}", rx.recv().unwrap());
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..3 {
let counter = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut number = counter.lock().unwrap();
*number += 1;
}));
}
for handle in handles {
handle.join().unwrap();
}
println!("counter = {}", *counter.lock().unwrap());
}
- Observed result:
received = hello from thread
counter = 3
4. Async was more accurate to document through requirements than through an unverified example
- Direct result: in this verification pass, only standard-library examples were rerun locally.
- Confirmed requirement: the
#[tokio::main]examples in the post require a Cargo dependency like the following before they can run.
[dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
- Interpretation from verification: for this post, it was more accurate to separate “directly rerun code” from “runtime-dependent async setup” than to present both as if they had been verified in the same way.
Interpretation / Opinion
- Interpretation: modules, smart pointers, concurrency, and async are easier to learn as tools for different layers of program design, not as disconnected syntax topics.
- Opinion: beginners usually understand
RcvsArcandRefCellvsMutexfaster when they are first framed by role, such as single-thread sharing, runtime borrow checking, or multi-thread shared state. - Opinion: async should be introduced as a separate execution model for waiting-heavy work, not as a simple replacement for threads.
Limits and Exceptions
- This post stays at the beginner-example level. Custom executors, async streams, actor models, and lock-free concurrency are outside the scope.
- Thread output order and timing are not deterministic and can vary across runs.
RefCell<T>is flexible, but because it checks some borrow rules at runtime, misuse can lead to a panic.- Async examples were not rerun locally in this pass because they depend on an added runtime such as Tokio.
References
- Hello, Cargo!
- Managing Growing Projects with Packages, Crates, and Modules
- Smart Pointers
- [Using Box
to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) - [Rc
, the Reference Counted Smart Pointer](https://doc.rust-lang.org/book/ch15-04-rc.html) - [RefCell
and the Interior Mutability Pattern](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html) - Fearless Concurrency
- Asynchronous Programming in Rust
댓글남기기