Rust: พื้นฐานสำหรับนักพัฒนาที่มีประสบการณ์ในปี 2026
เรียนรู้ Rust ได้อย่างรวดเร็วโดยอาศัยความรู้ด้านการเขียนโปรแกรมที่มีอยู่ Ownership, borrowing, lifetimes และ pattern ที่จำเป็นอธิบายไว้สำหรับนักพัฒนาที่มาจาก C++, Java หรือ Python

Rust ยังคงได้รับความนิยมเพิ่มขึ้นอย่างต่อเนื่องในทุกปี และเหตุผลนั้นชัดเจน: การรับประกันความปลอดภัยของหน่วยความจำในเวลาคอมไพล์ ประสิทธิภาพระดับเดียวกับ C++ และระบบนิเวศที่ทันสมัย สำหรับนักพัฒนาที่มีประสบการณ์จาก C++, Java หรือ Python การเรียนรู้ Rust อาจรู้สึกสับสนในตอนแรก แต่แนวคิดพื้นฐานจะกลายเป็นสิ่งที่เข้าใจได้อย่างเป็นธรรมชาติเมื่อเข้าใจอย่างถ่องแท้แล้ว
Rust ครองตำแหน่งภาษาที่นักพัฒนาชื่นชอบมากที่สุดบน Stack Overflow ติดต่อกัน 8 ปี ถูกนำไปใช้โดย Microsoft, Google, Amazon และ Meta สำหรับส่วนประกอบที่สำคัญ Rust มอบความปลอดภัยของหน่วยความจำโดยไม่ต้องใช้ garbage collector
การตั้งค่าสภาพแวดล้อม Rust
ก่อนเริ่มเขียนโค้ด จำเป็นต้องติดตั้ง Rust ผ่าน rustup ซึ่งเป็นเครื่องมือจัดการเวอร์ชันอย่างเป็นทางการ
# install.sh
# Install Rust via rustup (macOS, Linux)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Verify installation
rustc --version
cargo --versionCargo คือตัวจัดการแพ็กเกจและเครื่องมือ build ของ Rust โดย Cargo รวมฟังก์ชันการทำงานของ npm, Maven และ Make ไว้ในเครื่องมือเดียวที่สอดคล้องกัน
# project-setup.sh
# Create a new project
cargo new my_project
cd my_project
# Generated structure:
# my_project/
# ├── Cargo.toml # Manifest (like package.json)
# └── src/
# └── main.rs # Entry point
# Essential commands
cargo build # Compile the project
cargo run # Compile and run
cargo test # Run tests
cargo check # Check without building (faster)ตัวแปรและความไม่เปลี่ยนแปลงโดยค่าเริ่มต้น
Rust กลับด้านแนวปฏิบัติทั่วไป: ตัวแปรเป็น immutable โดยค่าเริ่มต้น แนวทางนี้บังคับให้นักพัฒนาคิดอย่างชัดเจนเกี่ยวกับ mutability และป้องกันบั๊กได้หลายประเภท
fn main() {
// Immutable by default
let x = 5;
// x = 6; // Compile error!
// Explicitly mutable variable
let mut y = 5;
y = 6; // OK
// Shadowing: redeclaration in the same scope
let x = x + 1; // Creates a new variable x
let x = x * 2; // x is now 12
// Shadowing also allows changing the type
let spaces = " "; // &str
let spaces = spaces.len(); // usize
}Shadowing สร้างตัวแปรใหม่ ซึ่งต่างจาก mut ที่เปลี่ยนแปลงค่าของตัวแปรเดิม Shadowing อนุญาตให้แปลงค่าในขณะที่ยังคงรักษาชื่อตัวแปรที่ชัดเจนไว้ได้
ชนิดข้อมูลพื้นฐาน
Rust เป็นภาษาแบบ statically typed ที่มีความสามารถในการอนุมานชนิดข้อมูลที่ยอดเยี่ยม ต่อไปนี้คือชนิดข้อมูล primitive ที่จำเป็นต้องรู้
fn main() {
// Signed integers: i8, i16, i32, i64, i128, isize
let age: i32 = 30;
// Unsigned integers: u8, u16, u32, u64, u128, usize
let count: u64 = 1_000_000; // Underscores for readability
// Floats: f32, f64 (default)
let pi: f64 = 3.14159;
// Boolean
let active: bool = true;
// Unicode character (4 bytes)
let emoji: char = '🦀';
// Tuple: fixed collection of different types
let person: (String, i32) = (String::from("Alice"), 28);
let (name, age) = person; // Destructuring
// Array: fixed size, same type
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
let first = numbers[0];
// Slice: view into a portion of data
let slice: &[i32] = &numbers[1..4]; // [2, 3, 4]
}Ownership: แนวคิดที่เปลี่ยนแปลงวงการ
Ownership คือนวัตกรรมหลักของ Rust ระบบนี้รับประกันความปลอดภัยของหน่วยความจำโดยไม่ต้องใช้ garbage collector แลกกับเส้นทางการเรียนรู้ในช่วงเริ่มต้น
กฎสามข้อของ Ownership
fn main() {
// Rule 1: Each value has a single owner
let s1 = String::from("hello");
// Rule 2: When the owner goes out of scope, the value is freed
{
let s2 = String::from("world");
// s2 is valid here
}
// s2 is dropped, no longer accessible
// Rule 3: Only one ownership at a time (move)
let s3 = s1; // s1 is MOVED to s3
// println!("{}", s1); // Error: s1 is no longer valid!
println!("{}", s3); // OK: s3 is the owner
}Move และ Clone
fn main() {
// Simple types (stack): automatic Copy
let x = 5;
let y = x; // Copy, not move
println!("x = {}, y = {}", x, y); // Both are valid
// Complex types (heap): Move by default
let s1 = String::from("hello");
let s2 = s1; // Move
// s1 is no longer usable
// Explicit clone to duplicate
let s3 = String::from("world");
let s4 = s3.clone(); // Deep copy
println!("s3 = {}, s4 = {}", s3, s4); // Both valid
}การส่งค่าไปยังฟังก์ชันจะทำให้ ownership ถูกโอนย้าย ฟังก์ชันจะกลายเป็นเจ้าของ และค่านั้นจะไม่สามารถเข้าถึงได้หลังจากเรียกใช้ เว้นแต่จะถูกส่งคืน
fn main() {
let s = String::from("hello");
takes_ownership(s);
// println!("{}", s); // Error: s has been moved
let x = 5;
makes_copy(x);
println!("{}", x); // OK: i32 implements Copy
// To regain ownership, return the value
let s2 = String::from("hello");
let s3 = takes_and_gives_back(s2);
println!("{}", s3); // OK
}
fn takes_ownership(s: String) {
println!("{}", s);
} // s is dropped here
fn makes_copy(x: i32) {
println!("{}", x);
}
fn takes_and_gives_back(s: String) -> String {
s // Returns ownership
}Borrowing: การอ้างอิงโดยไม่โอนความเป็นเจ้าของ
Borrowing อนุญาตให้ใช้ค่าโดยไม่ต้องรับ ownership กลไกนี้เป็นสิ่งที่ถูกใช้บ่อยที่สุดใน Rust
fn main() {
let s1 = String::from("hello");
// Immutable reference: read-only
let len = calculate_length(&s1);
println!("Length of '{}': {}", s1, len); // s1 still valid
// Mutable reference: modification allowed
let mut s2 = String::from("hello");
change(&mut s2);
println!("{}", s2); // "hello, world"
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s goes out of scope but doesn't drop (it's a reference)
fn change(s: &mut String) {
s.push_str(", world");
}กฎของ Borrowing
fn main() {
let mut s = String::from("hello");
// Rule 1: Multiple immutable references simultaneously OK
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
// Rule 2: ONLY ONE mutable reference at a time
let r3 = &mut s;
// let r4 = &mut s; // Error: already borrowed mutably
println!("{}", r3);
// Rule 3: No mutable ref if immutable ref exists
let r5 = &s;
// let r6 = &mut s; // Error: r5 is still active
println!("{}", r5);
// Once r5 is used for the last time, mutable borrow is allowed
let r7 = &mut s; // OK: r5 is no longer used after this
r7.push_str("!");
}พร้อมที่จะพิชิตการสัมภาษณ์ Rust แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
Lifetimes: การรับประกันความถูกต้องของการอ้างอิง
Lifetimes ช่วยให้มั่นใจว่า reference ยังคงถูกต้อง คอมไพเลอร์มักจะอนุมานได้โดยอัตโนมัติ แต่บางครั้งจำเป็นต้องมีการระบุ annotation อย่างชัดเจน
// Classic error: reference to freed data
// fn dangling() -> &String {
// let s = String::from("hello");
// &s // Error: s will be dropped, invalid reference!
// }
// Solution: return the owned value
fn no_dangle() -> String {
let s = String::from("hello");
s // Ownership transferred, no problem
}Lifetime Annotations
// The compiler can't figure out which reference will be returned
// fn longest(x: &str, y: &str) -> &str { ... } // Error!
// Explicit annotation: return lives as long as BOTH x AND y
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, &string2);
println!("Longest: {}", result); // OK here
}
// println!("{}", result); // Error: string2 dropped
}Rust ใช้กฎ elision เพื่อหลีกเลี่ยงการเขียน annotation ในกรณีที่ไม่ซับซ้อน สำหรับผู้เริ่มต้น การทำตามข้อความแจ้งเตือนที่ชัดเจนจากคอมไพเลอร์ถือว่าเพียงพอ
Struct และ Implementation
Struct เป็นส่วนประกอบพื้นฐานสำหรับการสร้างชนิดข้อมูลแบบกำหนดเองใน Rust
// Struct definition
#[derive(Debug)] // Enables printing with {:?}
struct User {
username: String,
email: String,
active: bool,
sign_in_count: u64,
}
// Implementation block for methods
impl User {
// Constructor (convention: fn new or descriptive name)
fn new(username: String, email: String) -> Self {
Self {
username,
email,
active: true,
sign_in_count: 1,
}
}
// Method: takes &self (reference to instance)
fn is_active(&self) -> bool {
self.active
}
// Method with mutation: takes &mut self
fn deactivate(&mut self) {
self.active = false;
}
// Method consuming self (rare)
fn into_username(self) -> String {
self.username
}
}
fn main() {
let mut user = User::new(
String::from("alice"),
String::from("alice@example.com"),
);
println!("Active: {}", user.is_active());
user.deactivate();
println!("Active: {}", user.is_active());
// Debug print
println!("{:?}", user);
}Enum และ Pattern Matching
Enum ใน Rust ทรงพลังกว่าภาษาส่วนใหญ่อย่างมาก เนื่องจากแต่ละ variant สามารถเก็บข้อมูลได้
// Simple enum
enum Direction {
North,
South,
East,
West,
}
// Enum with data (algebraic data type)
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
impl Message {
fn process(&self) {
match self {
Message::Quit => println!("Quitting"),
Message::Move { x, y } => println!("Moving to ({}, {})", x, y),
Message::Write(text) => println!("Writing: {}", text),
Message::ChangeColor(r, g, b) => {
println!("Color: rgb({}, {}, {})", r, g, b)
}
}
}
}
fn main() {
let msg = Message::Move { x: 10, y: 20 };
msg.process();
let msg2 = Message::Write(String::from("Hello Rust!"));
msg2.process();
}Option และ Result: การจัดการข้อผิดพลาด
use std::fs::File;
use std::io::{self, Read};
fn main() {
// Option<T>: present or absent value (replaces null)
let numbers = vec![1, 2, 3];
let first: Option<&i32> = numbers.first();
match first {
Some(n) => println!("First: {}", n),
None => println!("Empty list"),
}
// Utility methods
let value = first.unwrap_or(&0);
let doubled = first.map(|n| n * 2);
// Result<T, E>: success or error
let result = read_file("config.txt");
match result {
Ok(content) => println!("Content: {}", content),
Err(e) => println!("Error: {}", e),
}
}
fn read_file(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?; // ? propagates the error
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}ตัวดำเนินการ ? เป็น syntactic sugar สำหรับการส่งต่อข้อผิดพลาด ตัวดำเนินการนี้จะส่งคืนข้อผิดพลาดโดยอัตโนมัติหาก Result เป็น Err และจะ unwrap ค่า Ok ในกรณีที่สำเร็จ
Trait: Polymorphism แบบ Rust
Trait กำหนดพฤติกรรมที่ใช้ร่วมกัน คล้ายกับ interface ใน Java หรือ protocol ใน Swift
// Trait definition
trait Summary {
fn summarize(&self) -> String;
// Method with default implementation
fn preview(&self) -> String {
format!("{}...", &self.summarize()[..50.min(self.summarize().len())])
}
}
struct Article {
title: String,
author: String,
content: String,
}
struct Tweet {
username: String,
content: String,
}
// Implementation for Article
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
// Implementation for Tweet
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.content)
}
}
// Function accepting any type implementing Summary
fn notify(item: &impl Summary) {
println!("Breaking news: {}", item.summarize());
}
// Equivalent syntax with trait bound
fn notify_generic<T: Summary>(item: &T) {
println!("Breaking news: {}", item.summarize());
}
fn main() {
let article = Article {
title: String::from("Rust 2026"),
author: String::from("Community"),
content: String::from("..."),
};
let tweet = Tweet {
username: String::from("rustlang"),
content: String::from("Rust is awesome!"),
};
notify(&article);
notify(&tweet);
}Collection ที่จำเป็น
Rust มี collection ที่ทรงพลังใน standard library
use std::collections::HashMap;
fn main() {
// Vec<T>: dynamic array
let mut numbers: Vec<i32> = Vec::new();
numbers.push(1);
numbers.push(2);
numbers.push(3);
// vec! macro for initialization
let nums = vec![1, 2, 3, 4, 5];
// Iteration
for n in &nums {
println!("{}", n);
}
// Functional methods
let doubled: Vec<i32> = nums.iter().map(|x| x * 2).collect();
let sum: i32 = nums.iter().sum();
let evens: Vec<&i32> = nums.iter().filter(|x| *x % 2 == 0).collect();
// String: growable UTF-8 string
let mut s = String::from("Hello");
s.push_str(", World!");
s.push('!');
// Concatenation
let s1 = String::from("Hello, ");
let s2 = String::from("World!");
let s3 = s1 + &s2; // s1 moved, s2 borrowed
// or with format!
let s4 = format!("{}{}", "Hello, ", "World!");
// HashMap<K, V>
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Red"), 50);
// Access with get (returns Option)
if let Some(score) = scores.get("Blue") {
println!("Blue: {}", score);
}
// Entry API for conditional insertion
scores.entry(String::from("Yellow")).or_insert(25);
}การจัดการข้อผิดพลาดอย่างถูกวิธี
การจัดการข้อผิดพลาดที่เหมาะสมเป็นสิ่งจำเป็นใน Rust ต่อไปนี้คือ pattern ที่แนะนำ
use std::fs::File;
use std::io::{self, Read};
use std::num::ParseIntError;
// Define a custom error type
#[derive(Debug)]
enum AppError {
Io(io::Error),
Parse(ParseIntError),
Custom(String),
}
// Implement From for automatic conversion
impl From<io::Error> for AppError {
fn from(err: io::Error) -> Self {
AppError::Io(err)
}
}
impl From<ParseIntError> for AppError {
fn from(err: ParseIntError) -> Self {
AppError::Parse(err)
}
}
// Function returning Result with custom error
fn read_number_from_file(path: &str) -> Result<i32, AppError> {
let mut file = File::open(path)?; // io::Error -> AppError
let mut content = String::new();
file.read_to_string(&mut content)?;
let number: i32 = content.trim().parse()?; // ParseIntError -> AppError
Ok(number)
}
fn main() {
match read_number_from_file("number.txt") {
Ok(n) => println!("Number: {}", n),
Err(AppError::Io(e)) => println!("IO error: {}", e),
Err(AppError::Parse(e)) => println!("Parse error: {}", e),
Err(AppError::Custom(msg)) => println!("Error: {}", msg),
}
}สำหรับโปรเจกต์จริง crate thiserror (สำหรับ library) และ anyhow (สำหรับ application) ช่วยลดความซับซ้อนในการจัดการข้อผิดพลาดได้อย่างมาก
การทดสอบใน Rust
Rust มี testing framework ในตัวที่ถูกรวมเข้ากับภาษาโดยตรง
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Division by zero"))
} else {
Ok(a / b)
}
}
// Test module (compiled only for `cargo test`)
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_add_negative() {
assert_eq!(add(-1, 1), 0);
}
#[test]
fn test_divide_success() {
assert_eq!(divide(10, 2), Ok(5));
}
#[test]
fn test_divide_by_zero() {
assert!(divide(10, 0).is_err());
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_panic() {
let v = vec![1, 2, 3];
let _ = v[99]; // Panic!
}
}บทสรุป
Rust นำเสนอแนวคิดที่เป็นเอกลักษณ์ซึ่งผสมผสานความปลอดภัยของหน่วยความจำเข้ากับประสิทธิภาพสูง แนวคิด ownership และ borrowing อาจรู้สึกจำกัดในตอนแรก แต่จะกลายเป็นสิ่งที่เป็นธรรมชาติเมื่อฝึกฝนอย่างสม่ำเสมอ คอมไพเลอร์ของ Rust เป็นผู้ช่วยที่ล้ำค่า เนื่องจากข้อความแจ้งเตือนข้อผิดพลาดของ Rust ได้รับการยอมรับว่าเป็นหนึ่งในข้อความที่ดีที่สุดในอุตสาหกรรม
รายการตรวจสอบสำหรับการเริ่มต้น
- ติดตั้ง Rust ผ่าน rustup และเชี่ยวชาญการใช้ Cargo
- เข้าใจความแตกต่างระหว่าง immutability กับ explicit mutability
- เชี่ยวชาญกฎสามข้อของ ownership
- ฝึกฝน borrowing ด้วย reference
&และ&mut - ใช้
OptionและResultแทน null และ exception - เขียน test ด้วย
#[test]
เริ่มฝึกซ้อมเลย!
ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ
ชุมชน Rust เป็นชุมชนที่เป็นมิตรและมีทรัพยากรการเรียนรู้อย่างอุดมสมบูรณ์ หนังสือทางการ "The Rust Programming Language" สามารถอ่านได้ฟรีทางออนไลน์ ด้วยพื้นฐานที่แข็งแกร่งเหล่านี้ นักพัฒนาจะพร้อมสำหรับการสำรวจหัวข้อขั้นสูง เช่น async/await, macro และ WebAssembly
แท็ก
แชร์
บทความที่เกี่ยวข้อง

Ownership และ Borrowing ใน Rust: คู่มือฉบับสมบูรณ์
เชี่ยวชาญระบบ ownership และ borrowing ของ Rust กฎความเป็นเจ้าของ การอ้างอิง lifetime และรูปแบบการจัดการหน่วยความจำขั้นสูง

คำถามสัมภาษณ์ Rust: คู่มือฉบับสมบูรณ์ 2026
25 คำถามสัมภาษณ์ Rust ที่พบบ่อยที่สุด Ownership, borrowing, lifetime, trait, async และ concurrency พร้อมคำตอบละเอียดและตัวอย่างโค้ด

ทำความเข้าใจ Ownership และ Borrowing ใน Rust อย่างลึกซึ้ง สำหรับนักพัฒนาและผู้เตรียมสอบสัมภาษณ์
บทความเจาะลึกระบบ Ownership และ Borrowing ของ Rust ตั้งแต่พื้นฐานจนถึงขั้นสูง พร้อมตัวอย่างโค้ดจริงและแนวทางแก้ปัญหา Compiler Error ที่พบบ่อย เหมาะสำหรับการเตรียมสัมภาษณ์งาน