ในยุคที่ซอฟต์แวร์ต้องรองรับความเร็วระดับ Millisecond และต้องปลอดภัยจากช่องโหว่ด้าน Memory อย่าง Buffer Overflow, Use-After-Free และ Data Race ภาษา Rust ได้กลายเป็นคำตอบที่โลกเทคโนโลยีรอคอย ด้วยระบบ Ownership ที่ไม่เหมือนใคร Rust ให้ทั้งความเร็วระดับ C/C++ และความปลอดภัยด้าน Memory โดยไม่ต้องพึ่ง Garbage Collector ทำให้เป็นภาษาที่ได้รับความนิยมสูงสุดติดต่อกันหลายปีซ้อนบน Stack Overflow Survey
บทความนี้จะสอน Rust ตั้งแต่พื้นฐานจนถึงระดับที่ใช้งานจริงได้ ครอบคลุมทุกแนวคิดหลักที่ทำให้ Rust แตกต่างจากภาษาอื่น ไม่ว่าจะเป็น Ownership, Borrowing, Lifetimes, Traits, Pattern Matching และ Concurrency รวมถึงการสร้าง Web Application ด้วย Rust Framework ยอดนิยม
Rust คืออะไร?
Rust คือภาษาโปรแกรมมิ่งระดับ System ที่พัฒนาโดย Mozilla Research เริ่มต้นในปี 2010 โดย Graydon Hoare และเปิดตัวเวอร์ชัน 1.0 ในปี 2015 ปัจจุบันดูแลโดย Rust Foundation ซึ่งมีบริษัทใหญ่อย่าง Google, Microsoft, Amazon, Meta และ Huawei เป็นสมาชิก
Rust ถูกออกแบบมาเพื่อแก้ปัญหาที่ C/C++ ทำไม่ได้ นั่นคือการให้ Memory Safety โดยไม่ต้องใช้ Garbage Collector ผ่านระบบ Ownership ที่ตรวจสอบ ณ เวลา Compile ทำให้โปรแกรมที่ผ่านการ Compile จะปราศจากปัญหา Memory ที่พบบ่อยในภาษา C/C++
ทำไมต้อง Rust?
- Memory Safety without GC — ระบบ Ownership ตรวจจับ Bug ตั้งแต่ตอน Compile ไม่มี Null Pointer, No Dangling References
- Zero-Cost Abstractions — ใช้ Feature ระดับสูง (Generics, Iterators, Traits) โดยไม่เสีย Performance เลย Compiler จะ Optimize ให้เหมือนเขียน Low-level
- Fearless Concurrency — ระบบ Type System ป้องกัน Data Race ตั้งแต่ Compile Time ทำให้เขียน Concurrent Code ได้อย่างมั่นใจ
- Performance ระดับ C/C++ — ไม่มี Runtime Overhead ไม่มี GC Pause เหมาะกับ System Programming, Game Engine, Embedded
- Modern Tooling — Cargo (Package Manager), Clippy (Linter), Rustfmt (Formatter), Rust Analyzer (IDE Support) ครบครัน
- Ecosystem ที่เติบโต — Crates.io มี Package กว่า 140,000+ ครอบคลุมทุกด้าน
ใครใช้ Rust?
- Mozilla — Servo Browser Engine, Firefox Components
- Google — Android OS, Chrome, Fuchsia
- Microsoft — Windows Kernel Components, Azure
- Amazon — Firecracker (VM for Lambda/Fargate), Bottlerocket OS
- Meta — Source Control (Mononoke), Backend Services
- Cloudflare — Pingora (Reverse Proxy ทดแทน Nginx)
- Discord — Infrastructure Services ที่ต้องการ Low Latency
- Linux Kernel — เริ่มรับ Rust เป็นภาษาที่สองในการเขียน Kernel ตั้งแต่ Linux 6.1
ติดตั้ง Rust ด้วย Rustup
Rustup คือ Official Toolchain Manager ของ Rust ใช้จัดการเวอร์ชัน Rust Compiler (rustc), Package Manager (Cargo) และ Component ต่างๆ
# ติดตั้ง Rustup (Linux/Mac)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Windows — ดาวน์โหลด rustup-init.exe จาก rustup.rs
# ตรวจสอบการติดตั้ง
rustc --version # Rust compiler
cargo --version # Package manager
rustup --version # Toolchain manager
# อัพเดท Rust
rustup update
# ติดตั้ง Component เพิ่มเติม
rustup component add clippy # Linter
rustup component add rustfmt # Formatter
rustup component add rust-src # Source code (สำหรับ IDE)
Cargo — Package Manager ของ Rust
Cargo เป็นมากกว่าแค่ Package Manager มันคือ Build System, Test Runner, Documentation Generator และ Package Publisher รวมอยู่ในเครื่องมือเดียว
# สร้างโปรเจกต์ใหม่
cargo new my_project # สร้าง Binary project
cargo new my_lib --lib # สร้าง Library project
# โครงสร้างโปรเจกต์ที่ได้:
# my_project/
# ├── Cargo.toml # ไฟล์ Config (คล้าย package.json)
# ├── src/
# │ └── main.rs # Entry point
# └── .gitignore
# คำสั่ง Cargo ที่ใช้บ่อย
cargo build # Compile (Debug mode)
cargo build --release # Compile (Release mode, optimized)
cargo run # Compile + Run
cargo test # Run tests
cargo check # ตรวจสอบ syntax โดยไม่ compile (เร็วมาก)
cargo clippy # Lint code
cargo fmt # Format code
cargo doc --open # Generate + เปิด documentation
Cargo.toml — ไฟล์ Config ของโปรเจกต์
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
description = "My awesome Rust project"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = "0.12"
[dev-dependencies]
criterion = "0.5"
[profile.release]
opt-level = 3
lto = true
Syntax พื้นฐานของ Rust
ตัวแปรและ Mutability
ใน Rust ตัวแปรเป็น Immutable (เปลี่ยนค่าไม่ได้) โดยค่าเริ่มต้น ต้องใช้ mut เพื่อทำให้เปลี่ยนค่าได้
fn main() {
// Immutable — เปลี่ยนค่าไม่ได้
let x = 5;
// x = 6; // Error! cannot assign twice to immutable variable
// Mutable — เปลี่ยนค่าได้
let mut y = 10;
y = 20; // OK
// Shadowing — ประกาศใหม่ซ้ำชื่อได้
let z = 5;
let z = z + 1; // z = 6
let z = z * 2; // z = 12
// Constants — ค่าคงที่ (ต้องระบุ Type)
const MAX_POINTS: u32 = 100_000;
}
Data Types
// Integer types
let a: i8 = -128; // -128 ถึง 127
let b: u8 = 255; // 0 ถึง 255
let c: i32 = 2_147_483_647; // Default integer type
let d: i64 = 9_223_372_036_854_775_807;
let e: usize = 100; // Platform-dependent (32/64-bit)
// Float types
let f: f32 = 3.14;
let g: f64 = 2.718281828; // Default float type
// Boolean
let is_active: bool = true;
// Character (4 bytes, Unicode)
let ch: char = 'ก'; // รองรับภาษาไทย!
// String types
let s1: &str = "Hello"; // String slice (borrowed)
let s2: String = String::from("Hello"); // Owned String
let s3 = "Hello".to_string(); // เหมือนกัน
// Tuple
let tup: (i32, f64, char) = (42, 6.28, 'A');
let (x, y, z) = tup; // Destructuring
let first = tup.0; // Access by index
// Array (Fixed size)
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 10]; // [0, 0, 0, ..., 0] (10 ตัว)
Functions
// Function พื้นฐาน
fn greet(name: &str) {
println!("Hello, {}!", name);
}
// Function ที่ Return ค่า
fn add(a: i32, b: i32) -> i32 {
a + b // ไม่ต้องใส่ semicolon = return expression
}
// Function หลาย Parameters
fn calculate_bmi(weight: f64, height: f64) -> f64 {
weight / (height * height)
}
// Generic Function
fn largest<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b }
}
fn main() {
greet("Rust");
let sum = add(3, 5);
println!("Sum: {}", sum); // Sum: 8
println!("Max: {}", largest(10, 20)); // Max: 20
}
Control Flow
// if-else (เป็น expression ได้)
let number = 7;
let result = if number > 5 { "big" } else { "small" };
// loop
let mut count = 0;
let value = loop {
count += 1;
if count == 10 {
break count * 2; // Return ค่าจาก loop ได้
}
};
// while
let mut n = 3;
while n > 0 {
println!("{}", n);
n -= 1;
}
// for (ใช้บ่อยที่สุด)
for i in 0..5 {
println!("{}", i); // 0, 1, 2, 3, 4
}
for i in 0..=5 {
println!("{}", i); // 0, 1, 2, 3, 4, 5 (inclusive)
}
let names = vec!["Alice", "Bob", "Charlie"];
for name in &names {
println!("{}", name);
}
Ownership System — หัวใจของ Rust
Ownership คือแนวคิดที่ทำให้ Rust แตกต่างจากภาษาอื่นทั้งหมด มันคือระบบที่ Compiler ใช้จัดการ Memory โดยไม่ต้องมี Garbage Collector ถ้าเข้าใจ Ownership ก็ถือว่าเข้าใจ Rust ไปครึ่งหนึ่งแล้ว
กฎ 3 ข้อของ Ownership
- ทุกค่า (value) มีเจ้าของ (owner) ได้แค่ หนึ่งเดียว ในเวลาเดียวกัน
- เมื่อ owner ออกจาก scope ค่านั้นจะถูก drop (ลบออกจาก memory) อัตโนมัติ
- เมื่อกำหนดค่าให้ตัวแปรใหม่ ownership จะ move ไปที่ตัวแปรใหม่ (ตัวเดิมใช้ไม่ได้อีก)
fn main() {
// Move semantics
let s1 = String::from("hello");
let s2 = s1; // s1 ถูก "move" ไปที่ s2
// println!("{}", s1); // Error! s1 ถูก move ไปแล้ว ใช้ไม่ได้
println!("{}", s2); // OK: "hello"
// Clone — คัดลอกจริงๆ (Deep copy)
let s3 = String::from("world");
let s4 = s3.clone(); // คัดลอก Data ใหม่
println!("{}, {}", s3, s4); // ทั้งคู่ใช้ได้
// Copy types (ชนิดที่อยู่บน Stack: i32, f64, bool, char)
let x = 42;
let y = x; // Copy (ไม่ใช่ Move)
println!("{}, {}", x, y); // ทั้งคู่ใช้ได้
// Ownership กับ Function
let name = String::from("Rust");
take_ownership(name); // name ถูก move เข้า function
// println!("{}", name); // Error! name ถูก move ไปแล้ว
}
fn take_ownership(s: String) {
println!("Got: {}", s);
} // s ถูก drop ตรงนี้
Borrowing (References)
เนื่องจาก Move ทำให้ตัวแปรเดิมใช้ไม่ได้ Rust จึงมีระบบ Borrowing ให้ "ยืม" ค่าไปใช้โดยไม่ต้องโอน Ownership
fn main() {
let s = String::from("hello");
// Immutable Borrow (&) — ยืมแบบอ่านอย่างเดียว
let len = calculate_length(&s); // ยืม s ไป
println!("'{}' has length {}", s, len); // s ยังใช้ได้!
// Mutable Borrow (&mut) — ยืมแบบแก้ไขได้
let mut text = String::from("hello");
change(&mut text);
println!("{}", text); // "hello, world"
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s เป็นแค่ reference ไม่ถูก drop
fn change(s: &mut String) {
s.push_str(", world");
}
// กฎของ Borrowing:
// 1. มี &mut ได้แค่ 1 ตัวในเวลาเดียวกัน (ป้องกัน Data Race)
// 2. มี & ได้หลายตัว (อ่านพร้อมกันได้)
// 3. ไม่มี & กับ &mut พร้อมกันได้ (อ่านกับเขียนพร้อมกันไม่ได้)
Lifetimes
Lifetime บอก Compiler ว่า Reference มีอายุนานเท่าไหร่ เพื่อป้องกัน Dangling Reference
// Lifetime annotation
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
println!("Longest: {}", result);
}
// result ใช้ไม่ได้ที่นี่ เพราะ string2 ถูก drop แล้ว
}
// Lifetime ใน Struct
struct Excerpt<'a> {
part: &'a str,
}
impl<'a> Excerpt<'a> {
fn level(&self) -> i32 {
3
}
}
fn first_word(s: &str) -> &str Compiler รู้ว่า Output lifetime = Input lifetime
Structs และ Enums
Structs
// กำหนด Struct
struct User {
username: String,
email: String,
age: u32,
active: bool,
}
impl User {
// Associated function (constructor)
fn new(username: String, email: String, age: u32) -> Self {
Self {
username,
email,
age,
active: true,
}
}
// Method (ใช้ &self)
fn display(&self) {
println!("{} ({}), age {}", self.username, self.email, self.age);
}
// Method ที่แก้ไขค่า (ใช้ &mut self)
fn deactivate(&mut self) {
self.active = false;
}
}
fn main() {
let mut user = User::new(
"alice".to_string(),
"alice@example.com".to_string(),
30,
);
user.display();
user.deactivate();
}
Enums และ Pattern Matching
// Enum พื้นฐาน
enum Direction {
North,
South,
East,
West,
}
// Enum กับ Data (ทรงพลังมาก!)
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
Color(u8, u8, u8),
}
// Pattern Matching ด้วย match
fn process_message(msg: Message) {
match msg {
Message::Quit => println!("Quit!"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Write: {}", text),
Message::Color(r, g, b) => println!("Color: ({}, {}, {})", r, g, b),
}
}
// match ต้อง Exhaustive (ครอบคลุมทุกกรณี)
fn describe_number(n: i32) -> &'static str {
match n {
1 => "one",
2 => "two",
3..=9 => "several",
10..=99 => "many",
_ => "a lot", // _ = catch-all
}
}
Error Handling — Result และ Option
Rust ไม่มี Exception! แต่ใช้ Type System (Result และ Option) ในการจัดการ Error ทำให้ Compiler บังคับให้คุณจัดการทุก Error Case
Option — ค่าที่อาจมีหรือไม่มี
// Option<T> = Some(T) | None
fn find_user(id: u32) -> Option<String> {
if id == 1 {
Some("Alice".to_string())
} else {
None
}
}
fn main() {
// Pattern matching
match find_user(1) {
Some(name) => println!("Found: {}", name),
None => println!("Not found"),
}
// if let (สั้นกว่า)
if let Some(name) = find_user(1) {
println!("Found: {}", name);
}
// unwrap_or — ค่า Default
let name = find_user(99).unwrap_or("Unknown".to_string());
// map — แปลงค่าข้างใน
let upper = find_user(1).map(|n| n.to_uppercase());
}
Result — สำเร็จหรือผิดพลาด
use std::fs;
use std::io;
// Result<T, E> = Ok(T) | Err(E)
fn read_file(path: &str) -> Result<String, io::Error> {
fs::read_to_string(path)
}
fn main() {
// Pattern matching
match read_file("config.txt") {
Ok(content) => println!("Content: {}", content),
Err(e) => println!("Error: {}", e),
}
// ? Operator — ส่ง Error ต่อ (ใช้ใน function ที่ return Result)
// ถ้า Ok → แกะค่า, ถ้า Err → return Err ทันที
}
fn process_config() -> Result<(), Box<dyn std::error::Error>> {
let content = fs::read_to_string("config.txt")?; // ? แทน match
let value: i32 = content.trim().parse()?;
println!("Value: {}", value);
Ok(())
}
// Custom Error
#[derive(Debug)]
enum AppError {
NotFound(String),
ParseError(String),
DatabaseError(String),
}
impl std::fmt::Display for AppError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
AppError::NotFound(msg) => write!(f, "Not found: {}", msg),
AppError::ParseError(msg) => write!(f, "Parse error: {}", msg),
AppError::DatabaseError(msg) => write!(f, "DB error: {}", msg),
}
}
}
.unwrap() ใน Production Code เพราะจะ Panic (Crash) ถ้าเป็น None/Err ให้ใช้ ? operator, unwrap_or, unwrap_or_else, หรือ match แทน
Traits และ Generics
Trait คือสิ่งที่คล้ายกับ Interface ในภาษาอื่น ใช้กำหนดพฤติกรรมร่วมกันระหว่าง Type ต่างๆ ส่วน Generics ช่วยให้เขียน Code ที่ทำงานกับหลาย Type ได้
// กำหนด Trait
trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn read_more(&self) -> String {
format!("Read more about {}...", self.summarize())
}
}
struct Article {
title: String,
author: String,
content: String,
}
struct Tweet {
username: String,
content: String,
}
// Implement Trait
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.content)
}
}
// Trait bound ใน function
fn notify(item: &impl Summary) {
println!("Breaking: {}", item.summarize());
}
// หรือเขียนแบบเต็ม
fn notify_full<T: Summary + std::fmt::Display>(item: &T) {
println!("News: {}", item.summarize());
}
// where clause (อ่านง่ายกว่าเมื่อมีหลาย bounds)
fn process<T, U>(t: &T, u: &U) -> String
where
T: Summary + Clone,
U: Summary + std::fmt::Debug,
{
format!("{} and {}", t.summarize(), u.summarize())
}
Derive Macros — Implement Trait อัตโนมัติ
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Point {
x: i32,
y: i32,
}
// สามารถ derive ได้:
// Debug — println!("{:?}", point)
// Clone — point.clone()
// Copy — implicit copy (stack types)
// PartialEq — point1 == point2
// Eq — full equality
// Hash — ใช้เป็น key ใน HashMap
// Default — Point::default()
// Serialize/Deserialize (จาก serde) — JSON/YAML etc.
Collections — Vec, HashMap, HashSet
use std::collections::HashMap;
use std::collections::HashSet;
fn main() {
// Vec — Dynamic Array
let mut numbers: Vec<i32> = Vec::new();
numbers.push(1);
numbers.push(2);
numbers.push(3);
// หรือใช้ macro
let names = vec!["Alice", "Bob", "Charlie"];
// Access
let first = &numbers[0]; // อาจ panic ถ้า out of bounds
let safe = numbers.get(10); // Return Option<&i32>
// Iterate
for n in &numbers {
println!("{}", n);
}
// Functional style
let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
let evens: Vec<&i32> = numbers.iter().filter(|x| *x % 2 == 0).collect();
let sum: i32 = numbers.iter().sum();
// HashMap — Key-Value
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("Alice".to_string(), 95);
scores.insert("Bob".to_string(), 87);
// Access
if let Some(score) = scores.get("Alice") {
println!("Alice: {}", score);
}
// Entry API — Insert if not exists
scores.entry("Charlie".to_string()).or_insert(70);
// Word frequency count
let text = "hello world hello rust hello";
let mut freq: HashMap<&str, u32> = HashMap::new();
for word in text.split_whitespace() {
*freq.entry(word).or_insert(0) += 1;
}
// HashSet — Unique values
let mut tags: HashSet<String> = HashSet::new();
tags.insert("rust".to_string());
tags.insert("programming".to_string());
tags.insert("rust".to_string()); // ซ้ำ ไม่เพิ่ม
println!("Tags count: {}", tags.len()); // 2
}
Modules และ Crates
Rust ใช้ระบบ Module เพื่อจัดระเบียบ Code และ Crate คือหน่วยของ Compilation (Library หรือ Binary)
// src/lib.rs หรือ src/main.rs
// กำหนด Module
mod database {
pub struct Connection {
pub host: String,
port: u16, // private
}
impl Connection {
pub fn new(host: &str, port: u16) -> Self {
Self {
host: host.to_string(),
port,
}
}
pub fn connect(&self) {
println!("Connecting to {}:{}", self.host, self.port);
}
}
pub mod queries {
pub fn find_all() {
println!("Finding all records...");
}
}
}
// ใช้งาน
use database::Connection;
use database::queries;
fn main() {
let conn = Connection::new("localhost", 5432);
conn.connect();
queries::find_all();
}
// แยกไฟล์:
// src/database.rs → mod database
// src/database/mod.rs → mod database (แบบ directory)
// src/database/queries.rs → mod queries (sub-module)
Concurrency ใน Rust
Rust ให้ Concurrency ที่ปลอดภัยผ่าน Type System โดย Compiler จะป้องกัน Data Race ตั้งแต่ Compile Time ผ่าน Trait Send และ Sync
Threads
use std::thread;
use std::sync::{Arc, Mutex};
fn main() {
// สร้าง Thread
let handle = thread::spawn(|| {
for i in 1..=5 {
println!("Thread: {}", i);
thread::sleep(std::time::Duration::from_millis(100));
}
});
// Main thread ทำงานต่อ
for i in 1..=3 {
println!("Main: {}", i);
thread::sleep(std::time::Duration::from_millis(150));
}
handle.join().unwrap(); // รอ thread จบ
// แชร์ Data ข้าม Thread ด้วย Arc + Mutex
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Counter: {}", *counter.lock().unwrap()); // 10
}
Channels — ส่งข้อมูลระหว่าง Thread
use std::sync::mpsc; // Multiple Producer, Single Consumer
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
// Producer thread
let tx1 = tx.clone();
thread::spawn(move || {
let messages = vec!["hello", "from", "thread 1"];
for msg in messages {
tx1.send(msg.to_string()).unwrap();
thread::sleep(std::time::Duration::from_millis(100));
}
});
thread::spawn(move || {
let messages = vec!["more", "from", "thread 2"];
for msg in messages {
tx.send(msg.to_string()).unwrap();
thread::sleep(std::time::Duration::from_millis(100));
}
});
// Consumer (main thread)
for received in rx {
println!("Got: {}", received);
}
}
Async/Await ด้วย Tokio
// Cargo.toml: tokio = { version = "1", features = ["full"] }
use tokio;
#[tokio::main]
async fn main() {
// Async function
let result = fetch_data("https://api.example.com/data").await;
println!("Result: {}", result);
// Concurrent tasks
let (r1, r2, r3) = tokio::join!(
fetch_data("https://api.example.com/1"),
fetch_data("https://api.example.com/2"),
fetch_data("https://api.example.com/3"),
);
// Spawn task (คล้าย thread แต่ lightweight)
let handle = tokio::spawn(async {
heavy_computation().await
});
let result = handle.await.unwrap();
}
async fn fetch_data(url: &str) -> String {
// จำลอง HTTP request
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
format!("Data from {}", url)
}
async fn heavy_computation() -> i32 {
42
}
Rust สำหรับ Web Development
Rust มี Web Framework หลายตัวที่มีประสิทธิภาพสูงมาก ด้วยความเร็วที่เหนือกว่า Node.js, Python, Go หลายเท่า
Actix-web
// Cargo.toml: actix-web = "4"
use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
#[actix_web::get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("Hello from Actix-web!")
}
#[actix_web::get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
let user = User {
id: path.into_inner(),
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
HttpResponse::Ok().json(user)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(index)
.service(get_user)
})
.bind("0.0.0.0:8080")?
.run()
.await
}
Axum (โดย Tokio Team)
// Cargo.toml: axum = "0.7", tokio = { version = "1", features = ["full"] }
use axum::{
routing::{get, post},
Json, Router, extract::Path,
};
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct User {
id: u32,
name: String,
}
async fn root() -> &'static str {
"Hello from Axum!"
}
async fn get_user(Path(id): Path<u32>) -> Json<User> {
Json(User {
id,
name: "Bob".to_string(),
})
}
#[derive(Deserialize)]
struct CreateUser {
name: String,
}
async fn create_user(Json(payload): Json<CreateUser>) -> Json<User> {
Json(User {
id: 1,
name: payload.name,
})
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(root))
.route("/users/:id", get(get_user))
.route("/users", post(create_user));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Rocket
// Cargo.toml: rocket = "0.5"
#[macro_use] extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"Hello from Rocket!"
}
#[get("/hello/<name>/<age>")]
fn hello(name: &str, age: u8) -> String {
format!("Hello, {}! You are {} years old.", name, age)
}
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![index, hello])
}
เปรียบเทียบ Rust vs C++ vs Go
| Feature | Rust | C++ | Go |
|---|---|---|---|
| Memory Safety | Compile-time (Ownership) | Manual (unsafe) | GC (runtime) |
| Performance | สูงมาก (= C++) | สูงมาก | สูง (แต่มี GC pause) |
| Learning Curve | สูง (Ownership, Lifetimes) | สูงมาก (undefined behavior) | ต่ำ (เรียนง่าย) |
| Concurrency | Compile-time safe | Manual (ง่ายผิด) | Goroutines (ง่ายมาก) |
| Compile Speed | ช้า | ช้า | เร็วมาก |
| Null Safety | ไม่มี null (ใช้ Option) | มี null pointer | มี nil |
| Error Handling | Result/Option (type-safe) | Exceptions | Multiple return values |
| Package Manager | Cargo (ดีมาก) | CMake, vcpkg (ซับซ้อน) | Go Modules |
| Ecosystem | เติบโตเร็ว (crates.io) | ใหญ่มาก (เก่าแก่) | ใหญ่ (cloud-native) |
| Use Cases | System, WebAssembly, CLI | Game, OS, Embedded | Cloud, Microservices |
เมื่อไหร่ควรใช้ Rust?
เหมาะกับ Rust
- System Programming — OS Components, Drivers, Embedded Systems
- Performance-Critical Services — Game Servers, Trading Systems, Database Engines
- WebAssembly (WASM) — Rust เป็นภาษาอันดับ 1 สำหรับ WASM
- CLI Tools — ripgrep, fd, bat, exa, starship เขียนด้วย Rust
- Network Programming — Proxy, Load Balancer, DNS Server
- Blockchain / Crypto — Solana, Polkadot, Near Protocol ใช้ Rust
อาจไม่เหมาะ
- Prototype/MVP ที่ต้องการความเร็วในการพัฒนา (ใช้ Python/JS ดีกว่า)
- โปรเจกต์ที่ทีมไม่มีประสบการณ์ Rust และมี Deadline กระชั้น
- Script สั้นๆ ที่ไม่ต้องการ Performance สูง
- Mobile App Development (ยังไม่มี Framework ที่ Mature)
Iterators และ Closures
Rust มี Iterator Pattern ที่ทรงพลังมาก ใช้แทน Loop ได้ในหลายกรณี และ Compiler จะ Optimize ให้เร็วเท่า Loop ปกติ (Zero-Cost Abstraction)
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Closure (anonymous function)
let add = |a: i32, b: i32| a + b;
println!("{}", add(3, 5)); // 8
// Iterator chains
let result: Vec<i32> = numbers.iter()
.filter(|&&x| x % 2 == 0) // เลือกเลขคู่
.map(|&x| x * x) // ยกกำลัง 2
.collect(); // รวบรวมเป็น Vec
// result = [4, 16, 36, 64, 100]
// fold (คล้าย reduce)
let sum: i32 = numbers.iter().fold(0, |acc, &x| acc + x);
// any / all
let has_even = numbers.iter().any(|&x| x % 2 == 0); // true
let all_positive = numbers.iter().all(|&x| x > 0); // true
// enumerate
for (i, val) in numbers.iter().enumerate() {
println!("[{}] = {}", i, val);
}
// zip
let names = vec!["Alice", "Bob", "Charlie"];
let ages = vec![30, 25, 35];
let people: Vec<_> = names.iter().zip(ages.iter()).collect();
// [("Alice", 30), ("Bob", 25), ("Charlie", 35)]
// chain
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let combined: Vec<&i32> = a.iter().chain(b.iter()).collect();
}
Testing ใน Rust
// Unit Tests (ใส่ในไฟล์เดียวกัน)
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
assert_eq!(add(-1, 1), 0);
}
#[test]
fn test_divide_ok() {
assert_eq!(divide(10.0, 2.0).unwrap(), 5.0);
}
#[test]
fn test_divide_by_zero() {
assert!(divide(10.0, 0.0).is_err());
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_panic() {
let v = vec![1, 2, 3];
let _ = v[99]; // panic!
}
}
# Run tests
cargo test # Run ทุก test
cargo test test_add # Run เฉพาะ test นี้
cargo test -- --nocapture # แสดง println! output
cargo test -- --test-threads=1 # Run ทีละ test
Useful Crates ยอดนิยม
| Crate | หน้าที่ | Downloads/เดือน |
|---|---|---|
serde | Serialization/Deserialization (JSON, YAML, TOML) | 50M+ |
tokio | Async Runtime | 30M+ |
reqwest | HTTP Client | 15M+ |
clap | CLI Argument Parser | 15M+ |
sqlx | Async SQL (Postgres, MySQL, SQLite) | 5M+ |
axum | Web Framework | 5M+ |
tracing | Structured Logging | 20M+ |
anyhow | Error Handling (Application) | 20M+ |
thiserror | Error Handling (Library) | 20M+ |
rayon | Data Parallelism | 10M+ |
แหล่งเรียนรู้ Rust
- The Rust Book — doc.rust-lang.org/book (คู่มือทางการ ฟรี)
- Rust by Example — doc.rust-lang.org/rust-by-example
- Rustlings — github.com/rust-lang/rustlings (แบบฝึกหัด)
- Exercism Rust Track — exercism.org/tracks/rust
- Zero To Production In Rust — หนังสือสอน Web Backend ด้วย Rust
- Rust Playground — play.rust-lang.org (ทดลองเขียนออนไลน์)
สรุป
Rust เป็นภาษาที่ท้าทายในการเรียนรู้ แต่ให้ผลตอบแทนที่คุ้มค่าอย่างมาก ด้วย Memory Safety ที่รับประกันโดย Compiler, Performance ระดับ C/C++ และระบบ Type System ที่ป้องกัน Bug ได้ตั้งแต่ก่อน Run โปรแกรม Rust จึงเป็นภาษาที่เหมาะสำหรับการสร้างซอฟต์แวร์ที่ต้องการทั้งความเร็วและความน่าเชื่อถือ
เริ่มต้นเรียน Rust ด้วย The Rust Book ทำแบบฝึกหัดจาก Rustlings แล้วลองสร้างโปรเจกต์จริง เช่น CLI Tool หรือ Web API ด้วย Axum เมื่อผ่านช่วง Learning Curve ของ Ownership ไปได้แล้ว คุณจะพบว่า Rust ทำให้คุณเขียน Code ที่ดีขึ้นในทุกภาษา เพราะแนวคิดเรื่อง Memory Management, Concurrency Safety และ Explicit Error Handling จะติดตัวคุณไปตลอด
ในปี 2026 Rust ไม่ใช่แค่ภาษาของ System Programmer อีกต่อไป แต่กำลังขยายไปสู่ Web Development, Cloud Infrastructure, Blockchain และ WebAssembly การลงทุนเรียน Rust วันนี้จึงเป็นการลงทุนที่คุ้มค่าสำหรับอนาคตของ Developer ทุกคน
