Files
Sprimo/skills/m01-ownership/comparison.md
2026-02-12 22:58:33 +08:00

223 lines
5.6 KiB
Markdown

# Ownership: Comparison with Other Languages
## Rust vs C++
### Memory Management
| Aspect | Rust | C++ |
|--------|------|-----|
| Default | Move semantics | Copy semantics (pre-C++11) |
| Move | `let b = a;` (a invalidated) | `auto b = std::move(a);` (a valid but unspecified) |
| Copy | `let b = a.clone();` | `auto b = a;` |
| Safety | Compile-time enforcement | Runtime responsibility |
### Rust Move vs C++ Move
```rust
// Rust: after move, 'a' is INVALID
let a = String::from("hello");
let b = a; // a moved
// println!("{}", a); // COMPILE ERROR
// Equivalent in C++:
// std::string a = "hello";
// std::string b = std::move(a);
// std::cout << a; // UNDEFINED (compiles but buggy)
```
### Smart Pointers
| Rust | C++ | Purpose |
|------|-----|---------|
| `Box<T>` | `std::unique_ptr<T>` | Unique ownership |
| `Rc<T>` | `std::shared_ptr<T>` | Shared ownership |
| `Arc<T>` | `std::shared_ptr<T>` + atomic | Thread-safe shared |
| `RefCell<T>` | (manual runtime checks) | Interior mutability |
---
## Rust vs Go
### Memory Model
| Aspect | Rust | Go |
|--------|------|-----|
| Memory | Stack + heap, explicit | GC manages all |
| Ownership | Enforced at compile-time | None (GC handles) |
| Null | `Option<T>` | `nil` for pointers |
| Concurrency | `Send`/`Sync` traits | Channels (less strict) |
### Sharing Data
```rust
// Rust: explicit about sharing
use std::sync::Arc;
let data = Arc::new(vec![1, 2, 3]);
let data_clone = Arc::clone(&data);
std::thread::spawn(move || {
println!("{:?}", data_clone);
});
// Go: implicit sharing
// data := []int{1, 2, 3}
// go func() {
// fmt.Println(data) // potential race condition
// }()
```
### Why No GC in Rust
1. **Deterministic destruction**: Resources freed exactly when scope ends
2. **Zero-cost**: No GC pauses or overhead
3. **Embeddable**: Works in OS kernels, embedded systems
4. **Predictable latency**: Critical for real-time systems
---
## Rust vs Java/C#
### Reference Semantics
| Aspect | Rust | Java/C# |
|--------|------|---------|
| Objects | Owned by default | Reference by default |
| Null | `Option<T>` | `null` (nullable) |
| Immutability | Default | Must use `final`/`readonly` |
| Copy | Explicit `.clone()` | Reference copy (shallow) |
### Comparison
```rust
// Rust: clear ownership
fn process(data: Vec<i32>) { // takes ownership
// data is ours, will be freed at end
}
let numbers = vec![1, 2, 3];
process(numbers);
// numbers is invalid here
// Java: ambiguous ownership
// void process(List<Integer> data) {
// // Who owns data? Caller? Callee? Both?
// // Can caller still use it?
// }
```
---
## Rust vs Python
### Memory Model
| Aspect | Rust | Python |
|--------|------|--------|
| Typing | Static, compile-time | Dynamic, runtime |
| Memory | Ownership-based | Reference counting + GC |
| Mutability | Default immutable | Default mutable |
| Performance | Native, zero-cost | Interpreted, higher overhead |
### Common Pattern Translation
```rust
// Rust: borrowing iteration
let items = vec!["a", "b", "c"];
for item in &items {
println!("{}", item);
}
// items still usable
// Python: iteration doesn't consume
// items = ["a", "b", "c"]
// for item in items:
// print(item)
// items still usable (different reason - ref counting)
```
---
## Unique Rust Concepts
### Concepts Other Languages Lack
1. **Borrow Checker**: No other mainstream language has compile-time borrow checking
2. **Lifetimes**: Explicit annotation of reference validity
3. **Move by Default**: Values move, not copy
4. **No Null**: `Option<T>` instead of null pointers
5. **Affine Types**: Values can be used at most once
### Learning Curve Areas
| Concept | Coming From | Key Insight |
|---------|-------------|-------------|
| Ownership | GC languages | Think about who "owns" data |
| Borrowing | C/C++ | Like references but checked |
| Lifetimes | Any | Explicit scope of validity |
| Move | C++ | Move is default, not copy |
---
## Mental Model Shifts
### From GC Languages (Java, Go, Python)
```
Before: "Memory just works, GC handles it"
After: "I explicitly decide who owns data and when it's freed"
```
Key shifts:
- Think about ownership at design time
- Returning references requires lifetime thinking
- No more `null` - use `Option<T>`
### From C/C++
```
Before: "I manually manage memory and hope I get it right"
After: "Compiler enforces correctness, I fight the borrow checker"
```
Key shifts:
- Trust the compiler's errors
- Move is the default (unlike C++ copy)
- Smart pointers are idiomatic, not overhead
### From Functional Languages (Haskell, ML)
```
Before: "Everything is immutable, copying is fine"
After: "Mutability is explicit, ownership prevents aliasing"
```
Key shifts:
- Mutability is safe because of ownership rules
- No persistent data structures needed (usually)
- Performance characteristics are explicit
---
## Performance Trade-offs
| Language | Memory Overhead | Latency | Throughput |
|----------|-----------------|---------|------------|
| Rust | Minimal (no GC) | Predictable | Excellent |
| C++ | Minimal | Predictable | Excellent |
| Go | GC overhead | GC pauses | Good |
| Java | GC overhead | GC pauses | Good |
| Python | High (ref counting + GC) | Variable | Lower |
### When Rust Ownership Wins
1. **Real-time systems**: No GC pauses
2. **Embedded**: No runtime overhead
3. **High-performance**: Zero-cost abstractions
4. **Concurrent**: Data races prevented at compile time
### When GC Might Be Preferable
1. **Rapid prototyping**: Less mental overhead
2. **Complex object graphs**: Cycles are tricky in Rust
3. **GUI applications**: Object lifetimes are dynamic
4. **Small programs**: Overhead doesn't matter