Fluxo de controle
if, e o bloco, são expressões
let sign = if x < 0 { -1 } else if x == 0 { 0 } else { 1 };
let v = { let t = compute(); t * 2 };O valor de um bloco é a sua expressão final; sem uma, o bloco tem tipo (). Um if usado como valor precisa ter um else, e os dois ramos precisam ter o mesmo tipo. Condições são bool; não são exigidos parênteses em volta delas.
Loops
fn count_up(n: i64): i64 {
let i: i64 = 0;
while i < n {
i += 1;
}
i
}// `loop` runs until something breaks out of it.
fn first_power_of_two_over(limit: i64): i64 {
let v: i64 = 1;
loop {
if v > limit { break; }
v = v * 2;
}
v
}fn sum_below(n: i64): i64 {
let total: i64 = 0;
for i in 0..n { // half-open integer range, only in `for`
total = total + i;
}
total
}
fn letters(text: string): i64 {
let n: i64 = 0;
for c in text { // the characters of a string, decoded
n += 1;
}
n
}Um for sobre um array produz os seus elementos, e tanto for quanto let recebem um padrão, então uma tupla é desmontada onde é feito o binding:
fn main(): i32 {
let scores = [("ana", 7), ("bia", 9)];
let best = 0;
for (name, score) in scores {
if score > best { best = score; }
println(`${name} scored ${score}`);
}
let (low, high) = (1, best);
println(`${low} to ${high}`);
0
}Um elemento de um array que a função não possui é um borrow no corpo do loop, não uma cópia.
break e continue agem sobre o loop em que estão escritos, e return sai da função. Chaves são obrigatórias em todo corpo. switch, do/while, o for (;;) no estilo de C, goto e breaks com rótulo não existem.
match
let area = match shape {
Shape.Circle(r) => r * r * PI,
Shape.Rect { w, h } => w * h,
Shape.Empty => 0.0,
};
match token.kind {
TokenKind.Plus | TokenKind.Minus => { /* the body */ } // or-pattern
TokenKind.Integer(n) if n > 100 => { /* the body */ } // guard
_ => { } // wildcard
}| Padrão | Casa com |
|---|---|
_ | qualquer coisa, sem binding |
name | qualquer coisa, e faz o binding dela |
literal (1, 'a', "s", true) | valor igual |
Enum.Variant, Enum.Variant(p, q), Enum.Variant { f: p, g } | aquela variant, com sub-padrões no payload |
Some(p), None, Ok(p), Err(p) | os casos de Option e Result |
(p, q) | tupla |
Struct { f: p, g } | destructuring de struct |
p | q | qualquer um dos dois padrões; as duas alternativas precisam fazer binding dos mesmos nomes, e quando fazem binding, a alternância fica no topo de um arm (Case(a) | Case(b)), nunca dentro de um payload |
p if cond | padrão mais guard, só no topo de um arm |
Três regras dão ao match a sua segurança:
- Todo
matché exaustivo. Ummatchnão exaustivo é um erro de compilação. - Um arm que nenhum valor alcança também é um erro. Um nome sozinho é o padrão que faz binding, não uma comparação:
match os { OS_LINUX => ..., _ => ... }com duas constantes faz o binding deOS_LINUXe deixa dois arms inalcançáveis. O jeito de comparar com uma constante éif os == OS_LINUX. - Bindings fazem borrow. Um nome que um padrão liga se refere ao lugar casado pela duração do arm: payloads Copy são copiados, todo outro payload é lido no lugar. Guardar, retornar ou passar um nome ligado a um parâmetro
takesé um move, e borrowing diz quando isso é permitido.
Arms são separados por ,; um arm com bloco não precisa de vírgula. Todos os corpos dos arms precisam ter o mesmo tipo quando o match é usado como valor.