Publié · en amélioration
Guide Rust · 2/6
Ce chapitre n'est disponible qu'en anglais pour le moment.
This chapter covers variables and mutability, functions, control flow (if, loop, while, for, match) and shadowing. Rust looks familiar if you know any C-family language, but one idea runs through everything: almost every construct is an expression that produces a value.
Bindings created with let are immutable by default. Add mut when a value needs to change. This makes intent obvious to readers: if there is no mut, the value stays put.
fn main() {
let x = 5;
// x = 6; // compile error: cannot assign twice to an immutable variable
let mut count = 0;
count += 1;
count += 1;
// Constants always need a type and use SCREAMING_SNAKE_CASE
const MAX_USERS: u32 = 100_000;
println!("x = {x}, count = {count}, max = {MAX_USERS}");
}The compiler infers most types, so annotations are optional; write let age: u8 = 30; when you want to be explicit. A const must be known at compile time and may live outside any function. Underscores in numeric literals like 100_000 are purely for readability.
Declaring a new variable with the same name shadows the previous one. Unlike mut, shadowing lets you change the type, and the new binding is immutable again once you are done transforming it.
fn main() {
let input = " ";
let input = input.len(); // was &str, now usize
println!("spaces: {input}");
let x = 5;
{
let x = x * 2; // only visible inside this block
println!("inner x = {x}"); // 10
}
println!("outer x = {x}"); // 5
}Shadowing shines when you convert a value into another representation of the same thing, such as parsing a string into a number. You avoid awkward names like input_str and input_num.
Functions are declared with fn. Parameter types are mandatory, and the return type follows ->. The final expression in the body is the return value, written without a trailing semicolon. Add a semicolon and it becomes a statement whose value is the unit type (). Use return for early exits.
fn add(a: i32, b: i32) -> i32 {
a + b // no semicolon, so this is the return value
}
fn sign(n: i32) -> &'static str {
if n < 0 {
return "negative";
}
if n == 0 { "zero" } else { "positive" }
}
fn main() {
let sum = add(2, 3);
// A block is an expression too
let doubled_plus_one = {
let t = sum * 2;
t + 1
};
println!("{sum} {doubled_plus_one} {}", sign(-4));
}By convention function names use snake_case. Definition order does not matter, so helpers can live below main.
An if condition must be a bool; integers are not implicitly truthy. Because if is an expression, you can write let grade = if score >= 90 { "A" } else { "B" }; as long as both branches have the same type.
Rust has three loops:
loop repeats until you break, and break value hands a result back.while runs as long as a condition holds.for walks over a range or collection, and is by far the most common.fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // becomes the value of the loop
}
};
println!("result = {result}"); // 20
let mut n = 3;
while n > 0 {
println!("{n}!");
n -= 1;
}
for i in 1..=3 {
println!("i = {i}"); // 1, 2, 3 (..= is inclusive)
}
let fruits = ["apple", "pear", "plum"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{index}: {fruit}");
}
// A label lets you break out of the outer loop directly
'outer: for a in 0..5 {
for b in 0..5 {
if a * b == 6 {
println!("found: {a} x {b}");
break 'outer;
}
}
}
}The range 0..5 excludes 5, while 1..=3 includes 3. Iterate backwards with (1..=3).rev().
match compares a value against patterns from top to bottom and runs the first arm that fits. The compiler checks that the match is exhaustive, so forgetting a case is a compile error rather than a production bug. Use _ as a catch-all.
fn classify(n: i32) -> &'static str {
match n {
0 => "zero",
1 | 2 | 3 => "small",
4..=9 => "single digit",
x if x < 0 => "negative", // a guard adds an extra condition
_ => "large",
}
}
fn main() {
for n in [0, 2, 7, -1, 42] {
println!("{n}: {}", classify(n));
}
// When only one pattern matters, if let is more concise
let maybe: Option<i32> = Some(3);
if let Some(v) = maybe {
println!("value: {v}");
}
}mut.if and blocks also produce values.loop, while and for; for with ranges (.., ..=) covers most cases.match must be exhaustive, so the compiler catches missing cases for you.
0 commentaire
Se connecter · Connectez-vous pour laisser un commentaire.
Soyez le premier à commenter.