In PHP
if checks truthiness. These values are falsy: 0, 0.0, "", "0", [], null, and false. The same list is in the numbers lesson. A ternary is the expression form of if.
range(5, 1) counts down: 5 4 3 2 1. A C-style for keeps the index in $i. break 2 leaves two loops. do { } while runs the body, then tests.
<?php
$n = 7;
$label = $n > 0 ? "positive" : "non-positive";
echo $label, "\n";
if ("0") {
echo "truthy\n";
} else {
echo "falsy\n";
}
foreach (range(5, 1) as $value) {
echo $value, " ";
}
echo "\n";
$nums = [10, 20, 30];
for ($i = 0; $i < count($nums); $i++) {
echo $i, ": ", $nums[$i], "\n";
}
for ($x = 0; $x < 3; $x++) {
for ($y = 0; $y < 3; $y++) {
if ($x === 1 && $y === 1) {
break 2;
}
echo "$x,$y\n";
}
}
In Rust
if is an expression. Both branches have the same type, and the condition is a bool. if 1 does not compile. if "0" does not compile.
loop runs until break. break can carry the value of the loop. while tests a bool before each pass. for walks a range or a shared collection (for item in &nums).
1..4 is 1, 2, 3. 1..=5 includes 5. (1..=5).rev() counts down. 5..1 is an empty range: rustc accepts it, and the loop body never runs. Clippy is what rejects it, via clippy::reversed_empty_ranges, which is deny by default when you run cargo clippy (or a setup that enables Clippy):
error: this range is empty so it will yield no values
--> src/main.rs:2:18
|
2 | for value in 5..1 {
| ^^^^
|
= note: `#[deny(clippy::reversed_empty_ranges)]` on by default
help: consider using the following if you are attempting to iterate over this range in reverse
|
2 - for value in 5..1 {
2 + for value in (1..5).rev() {
(1..5).rev() is 4, 3, 2, 1. Include both ends, as PHP range(5, 1) does, with (1..=5).rev().
.enumerate() gives the index. A label such as 'outer: lets break 'outer leave the outer loop. PHP's break 2 is that idea. continue skips the rest of this pass. continue 'outer starts the next pass of the labelled loop. Rust has no do while. A loop with break at the end of the body is that shape.
while let is the idiomatic loop for "keep going while this pattern matches". PHP developers often miss it. Popping a stack until it is empty is:
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("{top}");
}
fn main() {
let n = 7;
let label = if n > 0 { "positive" } else { "non-positive" };
println!("{label}");
let mut ticks = 0;
let found = loop {
ticks += 1;
if ticks == 4 {
break ticks;
}
};
println!("{found}");
let mut i = 0;
while i < 3 {
i += 1;
}
println!("{i}");
for value in 1..4 {
println!("{value}");
}
for value in (1..=5).rev() {
println!("rev {value}");
}
let nums = [10, 20, 30];
for item in &nums {
println!("{item}");
}
for (index, item) in nums.iter().enumerate() {
println!("{index}: {item}");
}
'outer: for x in 0..3 {
for y in 0..3 {
if x == 1 && y == 1 {
break 'outer;
}
println!("{x},{y}");
}
}
let mut step = 0;
loop {
step += 1;
println!("step {step}");
if step == 2 {
break;
}
}
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("pop {top}");
}
}
label is positive. found is 4. 1..4 prints 1, 2, 3. The countdown prints rev 5 through rev 1. The labelled loops print 0,0, 0,1, 0,2, and 1,0, then stop. step prints 1 and 2. The stack prints pop 3, pop 2, pop 1.
Watch for:
5..1compiles withrustcand yields nothing. Clippy denies it. Count down with(1..=5).rev(). Anifcondition is abool, including the falsy PHP values"0"and[].
Idiomatic Rust:
for item in &nums, and.enumerate()when you need the index.while letfor pattern loops.break 'outer/continue 'outeron a labelled loop.breakwith a value when the loop's result is a number.
Side by side
| PHP | Rust | |
|---|---|---|
if as a value |
Ternary | if / else, both branches the same type |
| Condition | Falsy list, including "0" and [] |
A bool |
| Count down | range(5, 1) |
(1..=5).rev(). 5..1 is empty (clippy denies it) |
| Index | for ($i = 0; ...) |
.enumerate() |
| Leave two loops | break 2 |
break 'outer |
| Pattern loop | while (($x = array_pop(...)) !== null) |
while let Some(x) = ... |
do while |
Body, then the test | loop, with break at the end |
Try it
Open src/main.rs in the Playground. 1..4 prints 1, 2, and 3. (1..=5).rev() prints 5 down to 1. Change break 'outer to break and run it again. The inner loop stops at 1,1, and the outer loop continues with 2,0.
Key takeaways
ifis an expression. The condition is abool, and both branches have one type.loopcanbreaka value.whiletests first.while letkeeps going while the pattern matches.forwalks..,..=, or&collection.5..1compiles withrustcand yields nothing. Clippy deniesreversed_empty_ranges.(1..=5).rev()counts down the wayrange(5, 1)does..enumerate()replaces$i.'outer:withbreak 'outerorcontinue 'outertargets the labelled loop. There is nodo while. Putbreakat the end of aloop.
What's next: Tuples and arrays