Most Rust syntax matches C++. Some code that compiles in C++ does not compile in Rust. The compiler errors look opaque at first. Later chapters explain why the compiler rejects these programs and how it detects the problems.
If you’ve written C++, most Rust syntax will feel familiar. Functions, structs, loops, and vectors work the same way.
1
2
3
| fn main() {
println!("Hello, world!");
}
|
1
2
3
4
5
| fn main() {
let x = 5;
let y = 10;
println!("{} + {} = {}", x, y, x + y);
}
|
1
2
3
4
5
6
7
8
| fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let result = add(3, 4);
println!("Result: {}", result);
}
|
1
2
3
4
5
| fn main() {
let v = vec![1, 2, 3, 4, 5];
println!("Vector: {:?}", v);
println!("Length: {}", v.len());
}
|
1
2
3
4
5
6
7
8
9
| struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("Point at ({}, {})", p.x, p.y);
}
|
1
2
3
4
5
6
7
| fn main() {
let mut count = 0;
while count < 5 {
println!("Count: {}", count);
count += 1;
}
}
|
Checkpoint
You see Rust syntax. You recognize it. You can read it.
These examples do not compile:
1
2
3
4
5
| fn main() {
let v = vec![1, 2, 3];
let w = v;
println!("{:?}", v);
}
|
1
| error[E0382]: borrow of moved value: `v`
|
1
2
3
4
5
6
| fn main() {
let mut v = vec![1, 2, 3];
let r = &v[0];
v.push(4);
println!("{}", r);
}
|
1
| error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
1
2
3
4
5
6
7
8
| fn main() {
let r;
{
let x = 5;
r = &x;
}
println!("{}", r);
}
|
1
| error[E0597]: `x` does not live long enough
|
1
2
3
4
5
6
| fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
}
|
1
| error[E0499]: cannot borrow `s` as mutable more than once at a time
|
1
2
3
4
5
6
7
8
| fn get_string() -> &String {
let s = String::from("hello");
&s
}
fn main() {
let s = get_string();
}
|
1
| error[E0106]: missing lifetime specifier
|
1
2
3
4
5
6
| fn main() {
let mut v = vec![1, 2, 3];
for x in &v {
v.push(*x);
}
}
|
1
| error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
1
2
3
4
5
6
| fn main() {
let mut v = vec![1, 2, 3];
let closure = || v.push(4);
println!("{:?}", v);
closure();
}
|
1
| error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
|
1
2
3
4
5
6
7
8
| use std::thread;
fn main() {
let v = vec![1, 2, 3];
thread::spawn(|| {
println!("{:?}", v);
});
}
|
1
| error[E0373]: closure may outlive the current function
|
1
2
3
4
5
6
7
8
9
| use std::rc::Rc;
use std::thread;
fn main() {
let rc = Rc::new(5);
thread::spawn(move || {
println!("{}", rc);
});
}
|
1
| error[E0277]: `Rc<i32>` cannot be sent between threads safely
|
These programs contain memory bugs. Rust’s compiler rejects all of them. C++ compiles them.
Checkpoint
You see buggy code you recognize. You know these bugs. You see Rust rejects them. You do not know how Rust detects them.
The dangling reference case:
1
2
3
4
5
6
7
8
| fn main() {
let r;
{
let x = 5;
r = &x;
}
println!("{}", r);
}
|
r refers to x. The block ends. x is gone. r points to nothing.
The C++ equivalent compiles and runs. It prints garbage, or crashes, or prints 5 by accident. The C++ standard leaves this behavior undefined.
1
2
3
4
5
6
7
8
| int main() {
int* r;
{
int x = 5;
r = &x;
}
printf("%d\n", *r);
}
|
Checkpoint
You see one example explained in detail. You connect the Rust error to C++ undefined behavior. You know Rust catches bugs C++ misses. You do not know how yet. You are curious.