Some people learn new programming languages best by looking at examples for how to do the same thing they know in one language is done in the other. Below is a syntax comparison table which can serve as a quick reference for common C++ constructs and their equivalents in Rust. It is not a comprehensive guide, but I hope it helps out a C++ developer looking for a quick reference to Rust syntax.
Comparing Idioms in Rust and C++
| Feature | Rust | C++ |
|---|---|---|
| Immutable Variable Declaration | let x: i32 = 5; (immutable by default) |
const int x = 5; |
| Mutable Variables | let mut x = 5; |
int x = 5; (mutable by default) |
| Type Inference | let x = 5; |
auto x = 5; |
| Constant Declaration | const MAX: i32 = 100; |
constexpr int MAX = 100; orconsteval int MAX_FN() { return 100; } |
| Function Declaration | |
|
| Implicit Return | |
|
| Immutable Reference | &T |
const T& |
| Mutable Reference | &mut T |
T& |
| Raw Pointer | *const T*mut T |
const T*T* |
| Struct Declaration |
|
|
| Struct Initialization | Person { id: uid, health: 100 } |
Person{uid, 100} or Person{.id = uid, .health = 100}(multiple initialization styles available in C++) |
| Struct Field Access | person.id |
person.id |
| Class/Method Implementation |
|
|
| Method with Self |
|
|
| Static Method | fn static_method() { /* ... */ } |
static void static_method() { /* ... */ }Note: 'static' in C++ has multiple meanings including file-scope lifetime, class-level function, and non-exported symbols |
| Interface/Trait |
|
|
| Implementing Interface |
|
|
| Generic Function |
|
|
| Associated Types |
|
|
| Enums (Tagged Union) |
|
|
| Pattern Matching |
|
|
| Optional Types | Option<T> (Some(T) or None) |
std::optional<T> |
| Error Handling | Result<T, E> (Ok(T) or Err(E)) |
std::expected<T, E> (C++23) |
| Error Propagation | let file = File::open("file.txt")?; |
No direct equivalent; uses exceptions or return codes |
| Automatic Trait Implementation | #[derive(Debug, Clone, PartialEq)] |
No direct equivalent (may change with C++26 reflection) |
| Memory Management |
|
|
| Destructors |
|
|
| Serialization | #[derive(Serialize, Deserialize)] |
Requires manual implementation or code generation (may change with C++26 reflection) |
| Print to Console | println!("Hello, {name}"); |
std::cout << "Hello, " << name << std::endl;std::println("Hello, {}", name); (C++23) |
| Debug Output | println!("{:?}", object); |
No direct equivalent; requires custom implementation |
| Pretty Debug Output | println!("{:#?}", object); |
No direct equivalent |
Rust vs C++ Type Equivalents
| Type | Rust | C++ |
|---|---|---|
| Boolean | bool |
bool |
| Character | char (Unicode scalar value, 4 bytes) |
char32_t (or wchar_t on some platforms) |
| Byte (Raw Data) | u8 (always unsigned) |
uint8_t or unsigned char (for guaranteed unsigned) |
| Unsigned Integers |
|
|
| Signed Integers |
|
|
| Floating Point | f32, f64 |
float, double |
| Unit Type | () (unit) |
void |
| Never Type | ! (never) |
[[noreturn]] void |
| Immutable Reference | &T |
const T& |
| Mutable Reference | &mut T |
T& |
| Raw Pointers | *const T, *mut T |
const T*, T* |
| Arrays | [T; N] |
std::array<T, N> or T[N] |
| Slices | &[T] |
std::span<T> (C++20) |
| Dynamic Array | Vec<T> |
std::vector<T> |
| String | String (UTF-8 encoded) |
std::string |
| String Slice | &str (UTF-8 encoded) |
std::string_view (C++17) |
| C Compatible String | CString, &CStr |
std::string, const char* |
| Nullable/Optional | Option<T> |
std::optional<T> (C++17) |
| Error Handling | Result<T, E> |
std::expected<T, E> (C++23) |
| Smart Pointer (Unique) | Box<T> |
std::unique_ptr<T> |
| Smart Pointer (Shared) | Rc<T> (single-threaded)Arc<T> (thread-safe) |
std::shared_ptr<T> |
| Weak Pointer | Weak<T> (from Rc/Arc) |
std::weak_ptr<T> |
| Hash Map | HashMap<K, V> |
std::unordered_map<K, V> |
| Ordered Map | BTreeMap<K, V> |
std::map<K, V> |
| Hash Set | HashSet<T> |
std::unordered_set<T> |
| Ordered Set | BTreeSet<T> |
std::set<T> |
| Double-Ended Queue | VecDeque<T> |
std::deque<T> |
| Linked List | LinkedList<T> |
std::list<T> |
| Priority Queue | BinaryHeap<T> |
std::priority_queue<T> |
| Tuple | (T1, T2, ...) |
std::tuple<T1, T2, ...> |
| Tagged Union | enum Variant { A(T1), B(T2), ... } |
std::variant<T1, T2, ...> (C++17) |
| Interior Mutability | Cell<T>, RefCell<T> |
mutable keyword |
| Thread-Safe Mutability | Mutex<T>, RwLock<T> |
std::mutex + T |
| Atomic Types | AtomicBool, AtomicUsize, etc. |
std::atomic<bool>, std::atomic<size_t>, etc. |
From the Field
The cheat-sheet above is for getting unstuck on syntax. The harder question is whether the migration is worth it. Two short clips from Victor Ciura, a 20-year C++ veteran now leading parts of the Rust adoption at Microsoft, are worth listening to:
First, on what porting a real C++ codebase actually looks like:
“For this component, the ported code was about 150,000 lines. And it was pretty much a natural translation, from C and C++ to Rust. It didn’t require a major re-architecting or rethinking of the component. It was fairly straightforward.”
— Victor Ciura, Principal Engineer at Microsoft (Rust in Production, S04E01)
Second, on whether the rewrites actually pay off — which is the part skeptics tend to push back on hardest:
“We have hard data that shows that components that have been rewritten are much more solid. And we can actually even formally prove some of them to be memory safe, both in terms of spatial and temporal safety.”
— Victor Ciura, Principal Engineer at Microsoft (Rust in Production, S04E01)
If you want a counterpoint on the cost side, Victor is also blunt about Rust compile times — though, fittingly for the audience of this guide, he frames it as a non-issue for C++ developers:
“People coming from C++ don’t complain about compile times. Only people coming from C# and .NET complain about compile times. C++ people are used to getting their coffee or reading the Reddits while they compile.”
— Victor Ciura, Principal Engineer at Microsoft (Rust in Production, S04E01)
Need Help Migrating from C++ to Rust?
Migrating a C++ codebase is one of the more involved transitions. The languages share many low-level concepts, but Rust’s ownership model requires a shift in how you structure code (no mutable aliases, no self-referential structs, etc.). I help engineering teams navigate that shift, from training and architecture reviews to hands-on migration support. Get in touch to talk about your project.