Rust so với C++, Go và Python
“Mình nên học Rust, hay Go, hay cứ ở lại với Python?” là một trong những câu hỏi phổ biến nhất khi mọi người mới biết đến Rust. Câu trả lời thật lòng là: tùy vào thứ bạn muốn xây dựng. Mọi ngôn ngữ trong trang này đều là ngôn ngữ tốt, được hàng triệu người sử dụng. Mỗi ngôn ngữ chọn một kiểu đánh đổi khác nhau.
Hãy hình dung các ngôn ngữ như những phương tiện giao thông. Xe thể thao, xe tải giao hàng và xe đạp đều “tốt” cả. Chỉ là bạn sẽ không dùng xe đạp để chở đồ đạc khi chuyển nhà. Trang này giải thích những sự đánh đổi đó bằng lời lẽ đơn giản, để bạn chọn đúng công cụ cho công việc của mình. Chúng ta sẽ cố gắng công bằng, kể cả khi nói về những điểm yếu của Rust.
Rust giỏi ở điểm nào
Phần tiêu đề “Rust giỏi ở điểm nào”Lời hứa chính của Rust là nhanh và an toàn cùng một lúc:
- Nhanh như C và C++. Rust biên dịch ra mã máy native và không có bộ thu gom rác (garbage collector), nên chương trình không bị khựng lại trong lúc dọn dẹp bộ nhớ.
- An toàn bộ nhớ mà không cần bộ thu gom rác. Các quy tắc quyền sở hữu (ownership) và mượn (borrowing) được kiểm tra lúc biên dịch. Cả những nhóm lỗi (dùng vùng nhớ đã giải phóng, tranh chấp dữ liệu giữa các luồng) bị loại bỏ trước khi chương trình kịp chạy.
- Công cụ tuyệt vời có sẵn. Chỉ một công cụ, Cargo, lo việc build code, tải thư viện, chạy test và tạo tài liệu. Công cụ định dạng code (
rustfmt) và công cụ lint (clippy) đều là hàng chính thức. - Thông báo lỗi hữu ích. Trình biên dịch thường chỉ cho bạn chính xác cách sửa vấn đề.
Lập trình viên có vẻ cũng thích nó: trong khảo sát lập trình viên Stack Overflow 2025 (tiếng Anh), Rust một lần nữa là ngôn ngữ “được ngưỡng mộ nhất”, nghĩa là phần lớn những ai đang dùng Rust đều muốn tiếp tục dùng nó.
Cùng một bài toán trong bốn ngôn ngữ
Phần tiêu đề “Cùng một bài toán trong bốn ngôn ngữ”Hãy bắt đầu với một việc nhỏ: cộng các số chẵn trong một danh sách. Đây là phiên bản Rust:
fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; let sum: i32 = numbers.iter().filter(|n| *n % 2 == 0).sum(); println!("Tổng các số chẵn: {sum}");}Kết quả:
Tổng các số chẵn: 12Cùng chương trình đó viết bằng C++:
#include <iostream>#include <vector>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6}; int sum = 0; for (int n : numbers) { if (n % 2 == 0) { sum += n; } } std::cout << "Tổng các số chẵn: " << sum << "\n";}Bằng Go:
package main
import "fmt"
func main() { numbers := []int{1, 2, 3, 4, 5, 6} sum := 0 for _, n := range numbers { if n%2 == 0 { sum += n } } fmt.Println("Tổng các số chẵn:", sum)}Và bằng Python:
numbers = [1, 2, 3, 4, 5, 6]total = sum(n for n in numbers if n % 2 == 0)print("Tổng các số chẵn:", total)Cả bốn đều in ra cùng một dòng. Python ngắn nhất, Go và C++ dùng một vòng lặp đơn giản, còn Rust dùng một chuỗi iterator với một closure (bạn cũng có thể viết vòng lặp for trong Rust). Với những chương trình nhỏ như thế này, khác biệt chủ yếu nằm ở phong cách. Khác biệt thật sự lộ ra ở những chương trình lớn hơn.
Rust so với C++
Phần tiêu đề “Rust so với C++”C++ và Rust nhắm vào cùng một mảng: chương trình chạy nhanh với toàn quyền kiểm soát bộ nhớ, như trình duyệt, game engine, cơ sở dữ liệu và hệ điều hành. Khác biệt lớn nằm ở chỗ ai kiểm tra rằng bộ nhớ được dùng đúng cách.
Trong C++, đó là bạn. Đây là một lỗi kinh điển. Trình biên dịch C++ chấp nhận đoạn code này mà không phàn nàn gì, nhưng push_back có thể chuyển vector sang vùng nhớ mới, nên first có thể trỏ vào vùng nhớ đã bị giải phóng:
std::vector<int> v = {1, 2, 3};int& first = v[0];v.push_back(4); // có thể chuyển bộ nhớ của vector đi chỗ khác...std::cout << first << "\n"; // ...nên dòng này có thể đọc vùng nhớ đã giải phóngCùng lỗi đó trong Rust thì không biên dịch được:
fn main() { let mut v = vec![1, 2, 3]; let first = &v[0]; v.push(4); println!("{first}");}error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable --> src/main.rs:4:5 |3 | let first = &v[0]; | - immutable borrow occurs here4 | v.push(4); | ^^^^^^^^^ mutable borrow occurs here5 | println!("{first}"); | ----- immutable borrow later used hereTrình biên dịch (luôn nói tiếng Anh) báo rằng không thể mượn v dưới dạng khả biến vì nó đang được mượn bất biến bởi first, và first còn được dùng ở dòng 5.
Điều này rất quan trọng trong thực tế. Nhóm Chromium cho biết khoảng 70% lỗi bảo mật nghiêm trọng của họ là vấn đề an toàn bộ nhớ (tiếng Anh). Nhóm Android của Google đã viết code mới bằng Rust được vài năm. Năm 2022 họ báo cáo không tìm thấy lỗ hổng an toàn bộ nhớ nào trong code Rust của Android (tiếng Anh), và năm 2025 là mật độ lỗ hổng an toàn bộ nhớ thấp hơn hơn 1000 lần so với code C và C++ của họ (tiếng Anh). Nhân Linux (tiếng Anh) cũng hỗ trợ code viết bằng Rust.
Công cụ: C++ có rất nhiều hệ thống build và trình quản lý gói, và các nhóm thường tốn khá nhiều thời gian cho việc thiết lập. Rust có một công cụ chuẩn duy nhất là Cargo, nên mọi dự án Rust đều build theo cùng một cách.
Độ khó khi học: cả hai đều khó. C++ rất đồ sộ, và nhiều quy tắc của nó chỉ học được khi mắc lỗi lúc chạy. Quy tắc của Rust thì nghiêm ngặt, nhưng trình biên dịch áp dụng và giải thích chúng, nên bạn học chúng ngay lúc biên dịch.
Chỗ C++ vẫn thắng: hàng chục năm code có sẵn, thư viện và lập trình viên giàu kinh nghiệm. Nếu công ty hay game engine của bạn được xây trên C++, thì C++ thường là lựa chọn thực tế. Rust có thể gọi code C, và gọi C++ qua các giao diện kiểu C, nhưng việc kết hợp chúng đòi hỏi công sức.
Rust so với Go
Phần tiêu đề “Rust so với Go”Go và Rust hay được so sánh với nhau vì cả hai đều hiện đại, đều là ngôn ngữ biên dịch, và đều được ưa chuộng để viết server và công cụ dòng lệnh. Nhưng chúng được thiết kế với những mục tiêu khác nhau.
Thu gom rác hay quyền sở hữu. Go dùng một bộ thu gom rác (tiếng Anh) để tìm và giải phóng vùng nhớ không dùng nữa trong lúc chương trình chạy. Nhờ vậy code Go dễ viết hơn: bạn không bao giờ phải nghĩ xem ai sở hữu một giá trị. Cái giá là tốn thêm chút bộ nhớ và CPU, cộng thêm những lần khựng ngắn. Rust không có bộ thu gom rác. Bộ nhớ được giải phóng ở một thời điểm biết trước, khi chủ sở hữu ra khỏi phạm vi (scope). Điều này cho hiệu năng dễ đoán hơn, nhưng bạn phải học quyền sở hữu và mượn.
Xử lý đồng thời. Goroutine và channel của Go nổi tiếng là dễ dùng. Đây là một ví dụ nhỏ bình phương ba số song song rồi cộng chúng lại:
results := make(chan int)
for n := 1; n <= 3; n++ { go func() { results <- n * n }()}
total := 0for i := 0; i < 3; i++ { total += <-results}fmt.Println("tổng:", total)Phiên bản Rust dùng luồng (thread) và một channel. Nó dài dòng hơn một chút: bạn phải clone bên gửi cho từng luồng và dùng move:
use std::sync::mpsc;use std::thread;
fn main() { let (tx, rx) = mpsc::channel();
for n in 1..=3 { let tx = tx.clone(); thread::spawn(move || { tx.send(n * n).unwrap(); }); } drop(tx); // đóng bản sao của chúng ta để vòng lặp bên dưới có thể kết thúc
let total: i32 = rx.iter().sum(); println!("tổng: {total}");}Kết quả:
tổng: 14Gõ thêm như vậy thì bạn được gì: Rust từ chối biên dịch code mà hai luồng có thể cùng lúc thay đổi một dữ liệu (một tranh chấp dữ liệu, data race). Trong Go, data race vẫn có thể xảy ra; Go cung cấp một bộ phát hiện race (tiếng Anh) để tìm chúng trong lúc chương trình chạy. Xem thêm ở bài Lập trình đồng thời.
Thời gian biên dịch. Go được tạo ra để biên dịch nhanh. Phần FAQ của Go nói rằng build một file thực thi lớn chỉ nên mất tối đa vài giây (tiếng Anh). Rust biên dịch chậm hơn, vì trình biên dịch phải kiểm tra và tối ưu nhiều hơn hẳn. Bạn sẽ thấy rõ điều này ở các dự án lớn.
Sự đơn giản. Go cố ý là một ngôn ngữ nhỏ, ít tính năng phải học, nên nhiều người thấy họ đọc code Go rất nhanh. Rust có nhiều tính năng hơn (trait, generic, lifetime, macro), mạnh hơn nhưng cũng mất nhiều thời gian học hơn.
Rust so với Python
Phần tiêu đề “Rust so với Python”Python và Rust rất khác nhau, và chúng thường được dùng cùng nhau chứ không phải để thay thế nhau.
Tốc độ. Python là ngôn ngữ thông dịch, nên code Python thuần phải tính toán nhiều sẽ chậm hơn rất nhiều so với code đã biên dịch. Đó là lý do các thư viện Python phổ biến thường làm phần việc nặng bằng C, C++ hoặc Rust ở bên dưới.
Kiểu dữ liệu. Trong Python, kiểu được kiểm tra trong lúc chương trình chạy. Hàm này chạy được với một con số nhưng lỗi với một chuỗi, và bạn chỉ phát hiện ra khi dòng đó được chạy:
def add_tax(price): return price * 1.2
print(add_tax(10)) # 12.0print(add_tax("10")) # TypeError: can't multiply sequence by non-int of type 'float'Python có gợi ý kiểu (type hint) tùy chọn, nhưng môi trường chạy Python không bắt buộc tuân theo chúng (tiếng Anh). Trong Rust, mọi kiểu đều được kiểm tra trước khi chương trình chạy:
fn add_tax(price: f64) -> f64 { price * 1.2}
fn main() { println!("{}", add_tax(10.0)); println!("{}", add_tax("10"));}error[E0308]: mismatched types --> src/main.rs:7:28 |7 | println!("{}", add_tax("10")); | ------- ^^^^ expected `f64`, found `&str` | | | arguments to this function are incorrectTrình biên dịch báo kiểu không khớp: hàm cần một f64 nhưng lại nhận được một &str.
Khi Python vẫn là công cụ tốt hơn: script nhanh, phân tích dữ liệu, học máy, notebook, tự động hóa, và dạy người mới bắt đầu. Hệ sinh thái khoa học dữ liệu của Python cực kỳ lớn, và bạn có thể thử một ý tưởng chỉ trong vài phút. Nếu chương trình của bạn dành phần lớn thời gian để chờ mạng hoặc cơ sở dữ liệu, tốc độ của Python thường không thành vấn đề.
Dùng cả hai: dự án PyO3 (tiếng Anh) cho phép bạn viết module Python bằng Rust, nên bạn có thể giữ nguyên code Python và chỉ chuyển phần chậm sang Rust. Một số công cụ Python nổi tiếng bản thân chúng được viết bằng Rust; ví dụ, khảo sát của Stack Overflow ghi nhận rằng trình quản lý gói Python uv được xây dựng bằng Rust (tiếng Anh).
So sánh đặt cạnh nhau
Phần tiêu đề “So sánh đặt cạnh nhau”Đây là những xu hướng chung, không phải quy tắc cứng nhắc. Một chương trình được viết tốt bằng bất kỳ ngôn ngữ nào ở đây đều có thể “đủ nhanh”.
| Rust | C++ | Go | Python | |
|---|---|---|---|---|
| Tốc độ | Rất nhanh, mã native, không có GC | Rất nhanh, mã native, không có GC | Nhanh, mã native có GC | Chậm hơn khi tính toán nặng bằng Python thuần |
| An toàn bộ nhớ | Kiểm tra lúc biên dịch (ngoài unsafe) |
Trách nhiệm của lập trình viên | Có GC; vẫn có thể có data race | Có GC; an toàn, nhưng lỗi kiểu xuất hiện lúc chạy |
| Độ khó khi học | Lúc đầu dốc | Dốc, và là một ngôn ngữ rất lớn | Nhẹ nhàng | Nhẹ nhàng nhất |
| Thời gian biên dịch | Hơi chậm | Hơi chậm (tùy dự án) | Rất nhanh | Không có bước biên dịch |
| Hệ sinh thái | Trẻ hơn, đang lớn mạnh; có sẵn Cargo | Khổng lồ và trưởng thành; nhiều công cụ build | Thư viện chuẩn mạnh, rất hợp viết server | Cực lớn, nhất là dữ liệu và ML |
| Ứng dụng điển hình | Công cụ CLI, server, code hệ thống, WebAssembly, nhúng | Game, trình duyệt, hệ thống hiệu năng cao và hệ thống cũ | Dịch vụ web, công cụ cloud và DevOps | Script, khoa học dữ liệu, ML, tự động hóa |
Khi nào nên chọn Rust?
Phần tiêu đề “Khi nào nên chọn Rust?”Hãy tự hỏi những câu sau:
- Bạn có cần tốc độ tối đa hoặc dùng ít bộ nhớ không, ví dụ game engine, cơ sở dữ liệu hay code chạy trên thiết bị nhỏ? Rust (hoặc C++) là lựa chọn rất tốt.
- Lỗi có gây tốn kém không? Code nhạy cảm về bảo mật, server chạy lâu dài, và code mà nhiều người phụ thuộc vào được lợi nhiều nhất từ việc kiểm tra lúc biên dịch của Rust.
- Bạn đang làm một công cụ dòng lệnh muốn chia sẻ cho người khác? Rust tạo ra một file binary duy nhất, chạy nhanh, không cần cài thêm runtime. Go cũng rất tuyệt ở mảng này.
- Bạn cần một dịch vụ web thật nhanh, với một nhóm còn mới với tất cả các ngôn ngữ này? Go có lẽ sẽ giúp bạn về đích sớm hơn. Rust cũng làm tốt (xem Dự án: Web API), nhưng thời gian học lâu hơn.
- Đó là một script nhanh, phân tích dữ liệu, hay thử nghiệm ML? Hãy dùng Python. Về sau, nếu một phần nào đó quá chậm, hãy dùng Rust thông qua PyO3.
- Có sẵn một codebase C++ lớn không? Tạm thời cứ dùng C++, hoặc đưa Rust vào những phần mới, tách biệt, giống như Android đã làm.
Còn nếu bạn chỉ muốn trở thành lập trình viên giỏi hơn: học Rust dạy bạn bộ nhớ thực sự hoạt động thế nào, và kiến thức đó giúp ích ở mọi ngôn ngữ khác.
Những nhược điểm thật sự của Rust
Phần tiêu đề “Những nhược điểm thật sự của Rust”Rust không hoàn hảo. Đây là những điều mọi người thấy vất vả nhất:
- Độ khó khi học là có thật. Những tuần đầu làm việc với borrow checker có thể khá bực bội. Hãy chuẩn bị tinh thần “vật lộn với trình biên dịch” một thời gian. Mọi thứ dễ hơn nhiều khi bạn đã hiểu quyền sở hữu.
- Thời gian biên dịch chậm hơn Go, nhất là với dự án lớn và bản build release.
- Một số thứ khó diễn đạt hơn. Dữ liệu dạng đồ thị với nhiều liên kết giữa các đối tượng, hoặc code chia sẻ nhiều trạng thái khả biến, cần đến những công cụ như con trỏ thông minh (smart pointer) và phải lên kế hoạch kỹ hơn.
- Hệ sinh thái còn trẻ. Ở một số mảng (ứng dụng GUI, một số thư viện khoa học), số lựa chọn trưởng thành ít hơn so với C++ hay Python.
- Ít người dùng hơn (ít nhất là hiện tại). Trong khảo sát Stack Overflow 2025 (tiếng Anh), số người trả lời rằng họ dùng Python (khoảng 58%) hay C++ (khoảng 24%) nhiều hơn hẳn Rust (khoảng 15%). Nghĩa là có ít lập trình viên Rust giàu kinh nghiệm hơn để tuyển, để hỏi, hay để học hỏi ở nơi làm việc.
- Nhiều code hơn cho những việc đơn giản. Như ví dụ channel đã cho thấy, Rust thường đòi bạn viết rõ ràng ở những chỗ mà ngôn ngữ khác dễ dãi hơn.
Tóm tắt
Phần tiêu đề “Tóm tắt”- Rust cho tốc độ ngang C++ cùng với an toàn bộ nhớ được kiểm tra lúc biên dịch, và có bộ công cụ tích hợp tuyệt vời.
- So với C++, Rust ngăn chặn cả những nhóm lỗi bộ nhớ trước khi chương trình chạy; C++ có nhiều code và thư viện sẵn có hơn hẳn.
- So với Go, Rust không có bộ thu gom rác và chặn data race ngay lúc biên dịch; Go đơn giản hơn và biên dịch nhanh hơn nhiều.
- So với Python, Rust nhanh hơn rất nhiều và kiểm tra kiểu trước khi chạy; Python viết nhanh hơn và thống trị mảng khoa học dữ liệu. PyO3 cho phép bạn kết hợp cả hai.
- Cái giá chính của Rust là độ khó ban đầu cao, biên dịch chậm hơn và hệ sinh thái còn trẻ.
Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Kiểm tra nhanh
1. Rust quản lý bộ nhớ mà không cần bộ thu gom rác bằng cách nào?
2. Đâu là một ưu điểm công bằng của Go so với Rust?
3. Bạn có một chương trình Python mà một hàm chạy quá chậm. Cách làm phổ biến là gì?
4. Trong ví dụ C++ và Rust, chuyện gì xảy ra với đoạn code giữ &v[0] rồi push thêm vào v?
Điểm: 0 / 4
Đọc thêm
Phần tiêu đề “Đọc thêm”- The Rust Programming Language — Introduction (tiếng Anh): Rust dành cho ai, theo chính lời của cuốn sách chính thức.
- Rust in Android: move fast and fix things — Google Security Blog (tiếng Anh): số liệu thực tế từ một nhóm lớn dùng Rust bên cạnh C và C++.
- Stack Overflow Developer Survey 2025 — Admired and Desired (tiếng Anh): lập trình viên cảm thấy thế nào về Rust, Go, Python, C++ và các ngôn ngữ khác.
- Go FAQ — Why did you create a new language? (tiếng Anh): mục tiêu thiết kế của chính Go, giúp bạn hiểu Go mạnh ở đâu.
- PyO3 user guide (tiếng Anh): cách viết phần mở rộng Python bằng Rust.